• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (c) 2022 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 { XMessage } = require("./message/XMessage");
17const { Lexer } = require("./hcs/lexer");
18const { Generator } = require("./hcs/Generator");
19const { Scr } = require("./engine/XDefine");
20const { XButton } = require("./engine/control/XButton");
21const { AttrEditor } = require("./AttrEditor");
22const { NapiLog } = require("./hcs/NapiLog");
23const { XSelect } = require("./engine/control/XSelect");
24const { NodeTools, DataType } = require("./hcs/NodeTools");
25const { ModifyNode } = require("./hcs/ModifyNode");
26
27function rgba(r, g, b, a) {
28    if (a == undefined) a = 255
29    return a << 24 | r << 16 | g << 8 | b
30}
31class MainEditor {
32    constructor() {
33        this.files_ = {}
34        this.nodeCount_ = {};
35        this.filePoint_ = null;
36        this.rootPoint_ = null;
37        this.nodePoint_ = null;
38        this.offX_ = 100;
39        this.offY_ = 100;
40        this.touchQueue_ = [];
41        this.keyQueue_ = [];
42        this.dropAll_ = {
43            locked: false,
44            oldx: -1,
45            oldy: -1
46        }
47        this.nodeBtns = [];
48        this.nodeMoreBtns = [];
49        this.nodeBtnPoint_ = 0;
50        this.nodeMoreBtnPoint_ = 0;
51        XMessage.gi().registRecvCallback(this.onReceive);
52        XMessage.gi().send("inited", "");
53        AttrEditor.gi().freshEditor();
54
55        this.sltInclude = new XSelect(["a", "b", "c"], "b");
56        this.sltInclude.registCallback(this.onSelectInclude)
57        NapiLog.registError(this.onError);
58        this.errorMsg_ = []
59        this.delay_ = 0;
60
61        this.selectNode_ = {
62            type: null,
63            pnode: null
64        };
65        this.btnCancelSelect_ = new XButton();
66
67        AttrEditor.gi().registCallback(this.onAttributeChange);
68
69        this.mousePos_ = {
70            x: 0,
71            y: 0
72        }
73    }
74
75    calcPostionY(data, y) {
76        data.posY = y;
77        let ty = y;
78        switch (data.type_) {
79            case 1://uint8
80            case 2://uint16
81            case 3://uint32
82            case 4://uint64
83                y += MainEditor.LINE_HEIGHT;
84                break;
85            case 5://string
86                y += MainEditor.LINE_HEIGHT;
87                break;
88            case 6://ConfigNode
89                for (let i in data.value_) {
90                    y = this.calcPostionY(data.value_[i], y)
91                }
92                break;
93            case 7://ConfigTerm
94                y = this.calcPostionY(data.value_, y)
95                break;
96            case 8://Array class attribute value
97                y += MainEditor.LINE_HEIGHT;
98                break;
99            case 9://Attribute equal to leaf
100                y += MainEditor.LINE_HEIGHT
101                break;
102            case 10://Delete attribute
103                y += MainEditor.LINE_HEIGHT
104                break;
105            case 11://bool
106                y += MainEditor.LINE_HEIGHT
107                break;
108            default:
109                NapiLog.logError("unknow" + data.type_);
110                break;
111        }
112        if (y > ty) {
113            data.posY = (ty + y - MainEditor.LINE_HEIGHT) / 2
114        }
115        return y > (ty + MainEditor.LINE_HEIGHT) ? y : (ty + MainEditor.LINE_HEIGHT);
116    }
117    getNodeText(data) {
118        switch (data.nodeType_) {
119            case 0://Data class nodes, not inheri
120                return data.name_;
121            case 3://Deletion class nodes
122                return data.name_ + " : delete";
123            case 4://Templete Class nodes
124                return "templete " + data.name_;
125            case 5://Data class nodes, inherit
126                return data.name_ + ' :: ' + data.ref_;
127            case 1://Copy class nodes
128                return data.name_ + " : " + data.ref_;
129            case 2://Reference modification class nodes
130                return data.name_ + " : &" + data.ref_;
131            default:
132                return "unknow node type";
133        }
134    }
135
136    drawNode(pm2f, s, size, x, y, color, borderColor, bkcolor) {
137        let w = pm2f.getTextWidth(s, size);
138        pm2f.drawRect(x - 3, y - 3, w + 20, 20 + 6, borderColor, 2);
139        pm2f.fillRect(x - 3, y - 3, w + 20, 20 + 6, bkcolor);
140        pm2f.drawText(s, size, x, y, 1, 1, 0, -1, -1, color);
141        return w;
142    }
143
144    arrayNodeProc(w, pm2f, data, offx, offy) {
145        let ss = "[" + data.value_.length + "]" + NodeTools.arrayToString(data)
146        if (ss.length > 32) {
147            ss = ss.substring(0, 29) + "..."
148        }
149        w = pm2f.drawText(ss, 18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xffffffff);
150    }
151
152    configNodeProc(w, pm2f, data, offx, offy, path) {
153        this.setNodeButton(pm2f, offx, offy + data.posY, w, 20, path, data);
154
155        if (data.value_.length > 0) {
156            this.setNodeMoreButton(pm2f, offx, offy + data.posY, w, 20, data);
157        }
158        if (data.type_ == 6) {
159            for (let i in data.value_) {
160                if (data.value_[i].parent_.type_ == 6 && data.value_[i].parent_.isOpen_) {
161                    this.drawObj(pm2f, data.value_[i], offx + w + 50, offy, path + ".");
162                    pm2f.drawLine(data.posX + w, offy + data.posY + 10,
163                        data.value_[i].posX, offy + data.value_[i].posY + 10, 0xffffffff, 2)
164                } else if (data.value_[i].parent_.type_ == 7) {
165                    this.drawObj(pm2f, data.value_[i], offx + w + 50, offy, path + ".");
166                    pm2f.drawLine(data.posX + w, offy + data.posY + 10,
167                        data.value_[i].posX, offy + data.value_[i].posY + 10, 0xffffffff, 2)
168                }
169                else {
170                    NapiLog.logInfo("Node collapse does not need to draw child node");
171                }
172            }
173        } else {
174            for (let i in data.value_) {
175                this.drawObj(pm2f, data.value_[i], offx + w + 50, offy, path + ".");
176                pm2f.drawLine(data.posX + w, offy + data.posY + 10,
177                    data.value_[i].posX, offy + data.value_[i].posY + 10, 0xffffffff, 2)
178            }
179        }
180    }
181    drawObj(pm2f, data, offx, offy, path) {
182        let w;
183        path += data.name_;
184        data.posX = offx;
185
186        switch (data.type_) {
187            case 1://uint8
188            case 2://uint16
189            case 3://uint32
190            case 4://uint64
191                w = pm2f.drawText(NodeTools.jinZhi10ToX(data.value_, data.jinzhi_),
192                    18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xE6000000);
193                break;
194            case 5://string
195                w = pm2f.drawText('"' + data.value_ + '"', 18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xE6000000);
196                break;
197            case 6://ConfigNode
198                var color = data.errMsg_ != null ? 0xE6FF0000 : 0xE6000000;
199                w = this.drawNode(pm2f, this.getNodeText(data), 18, offx, offy + data.posY,
200                color, rgba(196, 196, 196), 0xffffffff);
201                this.configNodeProc(w, pm2f, data, offx, offy, path)
202                break;
203            case 7://ConfigTerm
204                w = this.drawNode(pm2f, data.name_ + "=", 18, offx, offy + data.posY, 0xE6000000, rgba(244,145,38), 0xffffffff);
205                this.setNodeButton(pm2f, offx, offy + data.posY, w, 20, path, data);
206                this.drawObj(pm2f, data.value_, offx + w, offy, path);
207                break;
208            case 8://Array class attribute value
209                this.arrayNodeProc(w, pm2f, data, offx, offy);
210                break;
211            case 9://Attribute equal to leaf
212                w = pm2f.drawText("&" + data.value_, 18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xffff0000);
213                break;
214            case 10://Delete attribute
215                w = pm2f.drawText("delete", 18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xffff0000);
216                break;
217            case 11://bool
218                if (data.value_) w = pm2f.drawText("true", 18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xffff0000);
219                else w = pm2f.drawText("false", 18, offx, offy + data.posY, 1, 1, 0, -1, -1, 0xffff0000);
220                break;
221            default:
222                NapiLog.logError("unknow" + data.type_);
223                break;
224        }
225        if (data.errMsg_ != null) {
226            if (parseInt(this.delay_ / 10) % 2 == 0) {
227                pm2f.drawRect(offx - 5, offy + data.posY - 5, w + 10, 20 + 10, 0xffff0000, 3);
228            }
229            pm2f.drawText(data.errMsg_, 18, offx + w - 5, offy + data.posY + 5, 1, 1, 0, -1, -3, 0xffff0000);
230        }
231    }
232
233    setNodeButton(pm2f, x, y, w, h, path, node) {
234        if (this.nodePoint_ == node) {
235            pm2f.drawRect(x - 3, y - 3, w + 20, h + 6, 0xff487EB8, 3);
236        }
237        if (this.nodeBtnPoint_ >= this.nodeBtns.length) {
238            this.nodeBtns.push(new XButton());
239        }
240        let pbtn = this.nodeBtns[this.nodeBtnPoint_];
241        pbtn.move(x - 3, y - 3, w + 6, h + 6);
242        pbtn.name_ = path;
243        pbtn.node_ = node;
244        this.nodeBtnPoint_ += 1;
245    }
246
247    setNodeMoreButton(pm2f, x, y, w, h, node) {
248        if (this.nodeMoreBtnPoint_ >= this.nodeMoreBtns.length) {
249            this.nodeMoreBtns.push(new XButton());
250        }
251        let pbtn = this.nodeMoreBtns[this.nodeMoreBtnPoint_];
252        pbtn.move(x + w + 18, y - 3, 15, h + 6);
253        pbtn.draw();
254        pm2f.drawLine(x + w + 20, y + 10, x + w + 30, y + 10, 0xffffffff, 2)
255        if(!node.isOpen_){
256            pm2f.drawLine(x + w + 25, y + 5, x + w + 25, y + 15, 0xffffffff, 2)
257        }
258        pbtn.node_ = node;
259        this.nodeMoreBtnPoint_ += 1;
260    }
261
262    draw(pm2f) {
263        pm2f.fillRect(0, 0, Scr.logicw, Scr.logich, 0xff303030);
264
265        if (this.filePoint_ != null && this.filePoint_ in this.files_) {
266            let data = this.files_[this.filePoint_];
267            this.calcPostionY(data, 0);
268
269            this.nodeBtnPoint_ = 0;
270            this.nodeMoreBtnPoint_ = 0;
271            this.drawObj(pm2f, data, this.offX_, this.offY_, "");
272        }
273        this.sltInclude.move(10, 10, 200, 20).draw();
274
275        if (this.selectNode_.type != null) {
276            if (this.selectNode_.type == "change_target") {
277                pm2f.drawText("点击选择目标", 18, this.mousePos_.x, this.mousePos_.y, 1, 1, 0, -3, -3, 0xff487EB8);
278                this.btnCancelSelect_.name_ = "取消选择";
279            }
280            else if (this.selectNode_.type == "copy_node") {
281                pm2f.drawText("已复制" + this.selectNode_.pnode.name_, 18, this.mousePos_.x, this.mousePos_.y, 1,
282                    1, 0, -3, -3, 0xff487EB8);
283                this.btnCancelSelect_.name_ = "取消复制";
284            }
285            else if (this.selectNode_.type == "cut_node") {
286                pm2f.drawText("已剪切" + this.selectNode_.pnode.name_, 18, this.mousePos_.x, this.mousePos_.y, 1,
287                    1, 0, -3, -3, 0xff487EB8);
288                this.btnCancelSelect_.name_ = "取消剪切";
289            }
290
291            this.btnCancelSelect_.move(Scr.logicw - 250, Scr.logich - 30, 100, 20).draw();
292        }
293
294        if (this.errorMsg_.length > 0) {
295            let ts = (new Date()).getTime()
296            while (this.errorMsg_.length > 0 && this.errorMsg_[0][0] < ts) {
297                this.errorMsg_.shift();
298            }
299            for (let i in this.errorMsg_) {
300                let y = Scr.logich / 2 - this.errorMsg_.length * 20 + i * 20
301                let a = parseInt((this.errorMsg_[i][0] - ts) / 2);
302                if (a > 255) a = 255;
303                NapiLog.logError(a);
304                a = a << 24;
305                pm2f.fillRect(0, y, Scr.logicw, 20, 0xff0000 | a);
306                pm2f.drawText(this.errorMsg_[i][1], 18, Scr.logicw / 2, y, 1, 1, 0, -2, -1, 0xffffff | a);
307            }
308
309        }
310        this.delay_ += 1;
311        this.procAll();
312    }
313
314    buttonClickedProc(nodeBtns) {
315        if (this.selectNode_.type == null ||
316            (this.selectNode_.type == "copy_node" || this.selectNode_.type == "cut_node")) {
317            this.nodePoint_ = nodeBtns.node_;
318            AttrEditor.gi().freshEditor(this.filePoint_, this.nodePoint_);
319            return true;
320        }
321        //What can be copied: data does not inherit, copy class nodes, template class nodes and data class inheritance
322        if (this.selectNode_.type == "change_target") {
323            let pn = nodeBtns.node_;
324            if (pn.type_ == DataType.NODE) {
325                if (this.selectNode_.pnode.type_ == DataType.NODE) {
326                    if (NodeTools.getPathByNode(this.selectNode_.pnode.parent_) ==
327                        NodeTools.getPathByNode(pn.parent_)) {
328                        this.selectNode_.pnode.ref_ = pn.name_;
329                    }
330                    else {
331                        this.selectNode_.pnode.ref_ = NodeTools.getPathByNode(pn);
332                    }
333                }
334                else if (this.selectNode_.pnode.type_ == DataType.REFERENCE) {
335                    if (NodeTools.getPathByNode(this.selectNode_.pnode.parent_.parent_) ==
336                        NodeTools.getPathByNode(pn.parent_)) {
337                        this.selectNode_.pnode.value_ = pn.name_;
338                    }
339                    else {
340                        this.selectNode_.pnode.value_ = NodeTools.getPathByNode(pn);
341                    }
342                }
343
344                this.selectNode_.type = null;
345                AttrEditor.gi().freshEditor(this.filePoint_, this.nodePoint_);
346                this.onAttributeChange("writefile");
347            }
348        }
349        return true
350    }
351
352    dropAllLocked(msg, x, y) {
353        if (msg == 2) {
354            this.offX_ += (x - this.dropAll_.oldx);
355            this.offY_ += (y - this.dropAll_.oldy);
356            this.dropAll_.oldx = x;
357            this.dropAll_.oldy = y;
358        }
359        if (msg == 3) {
360            this.dropAll_.locked = false;
361        }
362    }
363
364    procTouch(msg, x, y) {
365        this.mousePos_.x = x;
366        this.mousePos_.y = y;
367        if (this.dropAll_.locked) {
368            this.dropAllLocked(msg, x, y);
369            return true;
370        }
371
372        if (this.sltInclude.procTouch(msg, x, y)) {
373            return true;
374        }
375
376        if (this.selectNode_.type != null) {
377            if (this.btnCancelSelect_.procTouch(msg, x, y)) {
378                if (this.btnCancelSelect_.isClicked()) {
379                    this.selectNode_.type = null;
380                }
381                return true;
382            }
383        }
384
385        for (let i = 0; i < this.nodeBtnPoint_; i++) {
386            if (this.nodeBtns[i].procTouch(msg, x, y)) {
387                let nodeBtns = this.nodeBtns[i];
388                if (nodeBtns.isClicked()) {
389                    this.buttonClickedProc(nodeBtns);
390                }
391                return true;
392            }
393        }
394
395        for (let i = 0; i < this.nodeMoreBtnPoint_; i++) {
396            if (this.nodeMoreBtns[i].procTouch(msg, x, y)) {
397                let nodeMoreBtn = this.nodeMoreBtns[i];
398                if (nodeMoreBtn.isClicked()) {
399                    this.buttonClickedProc(nodeMoreBtn);
400                    this.nodeMoreBtns[i].node_.isOpen_ = !this.nodeMoreBtns[i].node_.isOpen_;
401                }
402                return true;
403            }
404        }
405
406        //Drag screen
407        if (msg == 1 && !this.dropAll_.locked) {
408            this.dropAll_.locked = true;
409            this.dropAll_.oldx = x;
410            this.dropAll_.oldy = y;
411            return true;
412        }
413    }
414    procKey(k) {
415        if (k == "ctrl+c") {
416            if (this.nodePoint_ != null) {
417                this.selectNode_ = {
418                    type: "copy_node",
419                    pnode: this.nodePoint_
420                };
421            }
422        }
423        else if (k == "ctrl+x") {
424            if (this.nodePoint_ != null) {
425                this.selectNode_ = {
426                    type: "cut_node",
427                    pnode: this.nodePoint_
428                };
429            }
430        }
431        else if (k == "ctrl+v") {
432            if (this.selectNode_.type != null && this.nodePoint_ != null) {
433                let parent = this.nodePoint_
434                if (this.nodePoint_.type_ != DataType.NODE)
435                    parent = this.nodePoint_.parent_;
436                parent.value_.push(NodeTools.copyNode(this.selectNode_.pnode, parent))
437                if (this.selectNode_.type == "cut_node") {
438                    ModifyNode.deleteNode(this.selectNode_.pnode)
439                    this.selectNode_.type = null;
440                }
441                this.checkAllError();
442            }
443        }
444        else if (k == "Delete") {
445            if (this.nodePoint_ != null) {
446                ModifyNode.deleteNode(this.nodePoint_)
447                AttrEditor.gi().freshEditor();
448            }
449        }
450    }
451    procAll() {
452        while (this.touchQueue_.length > 0) {
453            let touch = this.touchQueue_.shift();
454            this.procTouch(touch[0], touch[1], touch[2]);
455        }
456
457        while (this.keyQueue_.length > 0) {
458            let k = this.keyQueue_.shift();
459            this.procKey(k);
460        }
461    }
462    onSelectInclude(sel) {
463        MainEditor.gi().filePoint_ = sel;
464        AttrEditor.gi().freshEditor();
465    }
466
467    nodeCount(data) {
468        let ret = 1;
469        switch (data.type_) {
470            case 1://uint8
471            case 2://uint16
472            case 3://uint32
473            case 4://uint64
474            case 5://string
475                break;
476            case 6://ConfigNode
477                for (let i in data.value_) {
478                    ret += this.nodeCount(data.value_[i]);
479                }
480                break;
481            case 7://ConfigTerm
482                ret += this.nodeCount(data.value_);
483                break;
484            case 8://Array class attribute value
485            case 9://Attribute equal to leaf
486            case 10://Delete attribute
487            case 11://bool
488                break;
489            default:
490                NapiLog.logError("unknow" + data.type_);
491                break;
492        }
493        return ret;
494    }
495    isNodeCountChanged(fn) {
496        if (!(fn in this.nodeCount_)) {
497            this.nodeCount_[fn] = -1;
498        }
499        let newcount = this.nodeCount(this.files_[fn]);
500        if (this.nodeCount_[fn] != newcount) {
501            this.nodeCount_[fn] = newcount;
502            return true;
503        }
504        return false;
505    }
506    onAttributeChange(type, value) {
507        let pme = MainEditor.gi();
508        if (type == "writefile") {
509            let data1 = Generator.gi().makeHcs(pme.filePoint_, pme.files_[pme.filePoint_])
510            if (pme.isNodeCountChanged(pme.filePoint_)) {
511                let data2 = []
512                for (let j in data1) {
513                    data2.push(data1.charCodeAt(j))
514                }
515                Lexer.FILE_AND_DATA[pme.filePoint_] = data2;
516                pme.parse(pme.filePoint_)
517                let t=NodeTools.getPathByNode(pme.nodePoint_);
518                if(t){
519                    pme.nodePoint_=NodeTools.getNodeByPath(pme.files_[pme.filePoint_],t)
520                }
521                else pme.nodePoint_= null;
522
523                // pme.nodePoint_ = null;
524                AttrEditor.gi().freshEditor(pme.filePoint_, pme.nodePoint_);
525            }
526            pme.checkAllError();
527            XMessage.gi().send("writefile", {
528                fn: pme.filePoint_,
529                data: data1
530            })
531        }
532        else if (type.substring(0, 13) == "change_target") {
533            pme.selectNode_.type = type;
534            pme.selectNode_.pnode = value;
535        }
536    }
537    onError(msg) {
538        // MainEditor.gi().errorMsg_.push([(new Date()).getTime() + 5000, msg])
539    }
540    onTouch(msg, x, y) {
541        this.touchQueue_.push([msg, x, y]);
542    }
543    onKey(k) {
544        this.keyQueue_.push(k)
545    }
546    onReceive(type, data) {
547        NapiLog.logError(type);
548        let me = MainEditor.gi();
549        if (type == "parse") {
550            me.parse(data)
551        }
552        else if (type == "filedata") {
553            Lexer.FILE_AND_DATA[data.fn] = data.data;
554            me.parse(data.fn)
555        }
556        else if (type == "freshfiledata") {
557            Lexer.FILE_AND_DATA[data.fn] = data.data;
558        }
559    }
560    parse(fn) {
561        if (this.rootPoint_ == null) {
562            this.rootPoint_ = fn
563        }
564        let t = Generator.gi().hcsToAst(fn);
565        if (!t) return;
566
567        let fs = []
568        for (let i in t) {
569            this.files_[i] = Generator.gi().astToObj(t[i].ast.astRoot_);
570            fs.push(i)
571        }
572        this.filePoint_ = this.rootPoint_;
573        this.sltInclude.resetList(fs, this.filePoint_)
574        AttrEditor.gi().setFiles(this.files_)
575
576        this.checkAllError();
577    }
578    checkAllError() {
579        NapiLog.clearError()
580        let n1 = Generator.gi().mergeObj(this.files_)
581        if (n1) {
582            n1 = Generator.gi().expandObj(n1)
583            if (NapiLog.getResult()[0])
584                return true;
585        }
586        return false;
587    }
588
589}
590MainEditor.LINE_HEIGHT = 30
591
592MainEditor.pInstance_ = null;
593MainEditor.gi = function () {
594    if (MainEditor.pInstance_ == null) MainEditor.pInstance_ = new MainEditor();
595    return MainEditor.pInstance_;
596}
597
598module.exports = {
599    MainEditor
600}