├── .gitattributes ├── LICENSE ├── README.md ├── assets ├── images │ ├── 1024x768.png │ ├── 640x480.png │ ├── 800x600.png │ ├── add.png │ ├── font1.png │ ├── font2.png │ ├── icon-create.png │ ├── icon-guide-grid.png │ ├── icon-guide-line.png │ ├── icon-history.png │ ├── icon-list.png │ ├── icon-texture.png │ ├── icon-view.png │ ├── move.png │ ├── resize-letter.png │ ├── resize.png │ └── visibility.png ├── js │ ├── dxt │ │ └── dxt.js │ ├── guidegrid.js │ ├── guideline.js │ ├── historydata.js │ ├── historytype.js │ ├── main.js │ ├── multipleselection.js │ ├── project.js │ ├── textdraw.js │ ├── txd │ │ ├── texturedictionary.js │ │ └── texturemanager.js │ ├── ui │ │ ├── buttonui.js │ │ ├── contextmenuui.js │ │ ├── dialogui.js │ │ ├── dialogui │ │ │ ├── createdialogui.js │ │ │ ├── exportdialogui.js │ │ │ ├── guidegriddialogui.js │ │ │ ├── guidelinedialogui.js │ │ │ ├── historydialogui.js │ │ │ ├── importdialogui.js │ │ │ ├── multipleselectiondialogui.js │ │ │ ├── textdrawlistdialogui.js │ │ │ ├── texturedictionarydialogui.js │ │ │ └── textureexplorerdialogui.js │ │ ├── drawableui.js │ │ ├── drawableui │ │ │ ├── fontui.js │ │ │ ├── optionsui.js │ │ │ ├── screenshotui.js │ │ │ └── textdrawui.js │ │ ├── entityui.js │ │ ├── fileboxui.js │ │ ├── listboxui.js │ │ ├── resizerui.js │ │ └── textboxui.js │ └── util.js └── style │ └── main.css └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Leonardo541 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TextDraw Editor for SA-MP 2 | 3 | A TextDraw Editor built in Vanilla JS 4 | 5 | :warning: Work in progress 6 | 7 | ## Features 8 | 9 | - TextDraw Editor browser-based 10 | - TextDraw Sprite supported 11 | - TextDraw draggable and resizable 12 | - Guide system (lines, grids) 13 | - Multiple Selection 14 | - Import / export *.pwn files 15 | 16 | ## Tested on 17 | 18 | - Chrome 106.0.5249.103 19 | - Firefox 102.3.0esr 20 | - Firefox 105.0.2 21 | 22 | Demo at https://leonardo541.github.io/TextDrawEditor/ 23 | -------------------------------------------------------------------------------- /assets/images/1024x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/1024x768.png -------------------------------------------------------------------------------- /assets/images/640x480.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/640x480.png -------------------------------------------------------------------------------- /assets/images/800x600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/800x600.png -------------------------------------------------------------------------------- /assets/images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/add.png -------------------------------------------------------------------------------- /assets/images/font1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/font1.png -------------------------------------------------------------------------------- /assets/images/font2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/font2.png -------------------------------------------------------------------------------- /assets/images/icon-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-create.png -------------------------------------------------------------------------------- /assets/images/icon-guide-grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-guide-grid.png -------------------------------------------------------------------------------- /assets/images/icon-guide-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-guide-line.png -------------------------------------------------------------------------------- /assets/images/icon-history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-history.png -------------------------------------------------------------------------------- /assets/images/icon-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-list.png -------------------------------------------------------------------------------- /assets/images/icon-texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-texture.png -------------------------------------------------------------------------------- /assets/images/icon-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/icon-view.png -------------------------------------------------------------------------------- /assets/images/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/move.png -------------------------------------------------------------------------------- /assets/images/resize-letter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/resize-letter.png -------------------------------------------------------------------------------- /assets/images/resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/resize.png -------------------------------------------------------------------------------- /assets/images/visibility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leonardo541/TextDrawEditor/51fd815ab21799fd476834cb29745229192293d7/assets/images/visibility.png -------------------------------------------------------------------------------- /assets/js/dxt/dxt.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Original source: https://github.com/LordVonAdel/dxtn (MIT License) 3 | */ 4 | 5 | const DXT1BlockSize = 8; 6 | const DXT3BlockSize = 16; 7 | 8 | const RGBABlockSize = 64; 9 | const BlockWidth = 4; 10 | const BlockHeight = 4; 11 | 12 | function getComponentsFromRGB565(color) 13 | { 14 | return {R: ((color & 0b11111000_00000000) >> 8) / 0xff, G: ((color & 0b00000111_11100000) >> 3) / 0xff, B: ((color & 0b00000000_00011111) << 3) / 0xff} 15 | } 16 | 17 | function generateDXT1Lookup(colorValue0, colorValue1) 18 | { 19 | let color0 = getComponentsFromRGB565(colorValue0); 20 | let color1 = getComponentsFromRGB565(colorValue1); 21 | 22 | let lookup = new Uint8Array(16); 23 | 24 | if(colorValue0 > colorValue1) 25 | { 26 | // Non transparent mode 27 | lookup[0] = Math.floor((color0.R) * 255); 28 | lookup[1] = Math.floor((color0.G) * 255); 29 | lookup[2] = Math.floor((color0.B) * 255); 30 | lookup[3] = Math.floor(255); 31 | 32 | lookup[4] = Math.floor((color1.R) * 255); 33 | lookup[5] = Math.floor((color1.G) * 255); 34 | lookup[6] = Math.floor((color1.B) * 255); 35 | lookup[7] = Math.floor(255); 36 | 37 | lookup[8] = Math.floor((color0.R * 2/3 + color1.R * 1/3 ) * 255); 38 | lookup[9] = Math.floor((color0.G * 2/3 + color1.G * 1/3 ) * 255); 39 | lookup[10] = Math.floor((color0.B * 2/3 + color1.B * 1/3 ) * 255); 40 | lookup[11] = Math.floor(255); 41 | 42 | lookup[12] = Math.floor((color0.R * 1/3 + color1.R * 2/3) * 255); 43 | lookup[13] = Math.floor((color0.G * 1/3 + color1.G * 2/3) * 255); 44 | lookup[14] = Math.floor((color0.B * 1/3 + color1.B * 2/3) * 255); 45 | lookup[15] = Math.floor(255); 46 | } 47 | else 48 | { 49 | // transparent mode 50 | lookup[0] = Math.floor((color0.R) * 255); 51 | lookup[1] = Math.floor((color0.G) * 255); 52 | lookup[2] = Math.floor((color0.B) * 255); 53 | lookup[3] = Math.floor(255); 54 | 55 | lookup[4] = Math.floor((color0.R * 1/2 + color1.R * 1/2 ) * 255); 56 | lookup[5] = Math.floor((color0.G * 1/2 + color1.G * 1/2 ) * 255); 57 | lookup[6] = Math.floor((color0.B * 1/2 + color1.B * 1/2 ) * 255); 58 | lookup[7] = Math.floor(255); 59 | 60 | lookup[08] = Math.floor((color1.R) * 255); 61 | lookup[09] = Math.floor((color1.G) * 255); 62 | lookup[10] = Math.floor((color1.B) * 255); 63 | lookup[11] = Math.floor(255); 64 | 65 | lookup[12] = Math.floor(0); 66 | lookup[13] = Math.floor(0); 67 | lookup[14] = Math.floor(0); 68 | lookup[15] = Math.floor(0); 69 | } 70 | 71 | return lookup; 72 | } 73 | 74 | function decompressBlockDXT1(data, out) 75 | { 76 | if(data.length != DXT1BlockSize) return false; 77 | 78 | const cVal0 = (data[1] << 8) + data[0]; 79 | const cVal1 = (data[3] << 8) + data[2]; 80 | const lookup = generateDXT1Lookup(cVal0, cVal1); 81 | 82 | for(let i = 0; i < 16; i++) 83 | { 84 | let bitOffset = i * 2; 85 | let byte = 4 + Math.floor(bitOffset / 8); 86 | let bits = (data[byte] >> bitOffset % 8) & 3; 87 | 88 | out[i * 4 + 0] = lookup[bits * 4 + 0]; 89 | out[i * 4 + 1] = lookup[bits * 4 + 1]; 90 | out[i * 4 + 2] = lookup[bits * 4 + 2]; 91 | out[i * 4 + 3] = lookup[bits * 4 + 3]; 92 | } 93 | 94 | return out; 95 | } 96 | 97 | function decompressBlockDXT3(data, out) 98 | { 99 | decompressBlockDXT1(data.slice(8, 16), out); 100 | 101 | for(let i = 0; i < 8; i++) 102 | { 103 | out[i * 8 + 3] = (data[i] & 0x0f) << 4; 104 | out[i * 8 + 7] = (data[i] & 0xf0); 105 | } 106 | 107 | return out; 108 | } 109 | 110 | function decompressDXT(width, height, data, out, blockSize, blockDecompressMethod) 111 | { 112 | if(width % BlockWidth != 0) throw new Error("Width of the texture must be divisible by 4"); 113 | if(height % BlockHeight != 0) throw new Error("Height of the texture must be divisible by 4"); 114 | if(width < BlockWidth || height < BlockHeight) throw new Error("Size of the texture is to small"); 115 | 116 | let w = width / BlockWidth; 117 | let h = height / BlockHeight; 118 | let blockNumber = w * h; 119 | 120 | if(blockNumber * blockSize != data.length) throw new Error("Data does not match dimensions"); 121 | 122 | let blockBuffer = new Uint8Array(RGBABlockSize); 123 | 124 | for(let i = 0; i < blockNumber; i++) 125 | { 126 | let decompressed = blockDecompressMethod(data.slice(i * blockSize, (i + 1) * blockSize), blockBuffer); 127 | 128 | let pixelX = (i % w) * 4; 129 | let pixelY = Math.floor(i / w) * 4; 130 | 131 | let j = 0; 132 | 133 | for(let y = 0; y < 4; y++) 134 | { 135 | for(let x = 0; x < 4; x++) 136 | { 137 | let px = x + pixelX; 138 | let py = y + pixelY; 139 | 140 | out[px * 4 + py * 4 * width] = decompressed[j]; 141 | out[px * 4 + py * 4 * width + 1] = decompressed[j + 1]; 142 | out[px * 4 + py * 4 * width + 2] = decompressed[j + 2]; 143 | out[px * 4 + py * 4 * width + 3] = decompressed[j + 3]; 144 | 145 | j += 4; 146 | } 147 | } 148 | } 149 | 150 | return out; 151 | } 152 | -------------------------------------------------------------------------------- /assets/js/guidegrid.js: -------------------------------------------------------------------------------- 1 | 2 | function GuideGrid(main, internalId, name, x, y, width, height, margin, padding, rows, columns) 3 | { 4 | this.main = main; 5 | this.internalId = internalId; 6 | 7 | this.textDrawItemUI = new EntityUI(null, "div", {class: "textDrawItem", onclick: (e) => { if(e.shiftKey) { main.adjacentAnyObject(this, e.ctrlKey); } else if(e.ctrlKey) { main.toggleAnyObject(this); } else { main.changeGuideGrid(this); } }, contextmenu: (e) => { main.contextMenuGuideGrid(this, e.clientX, e.clientY); e.preventDefault(); }}); 8 | this.thumbnailUI = new EntityUI(this.textDrawItemUI, "img", { src: "./assets/images/icon-guide-grid.png", width: "24", height: "24", draggable: false }); 9 | this.nameUI = new EntityUI(this.textDrawItemUI, "span", {innerText: name}); 10 | this.visibilityUI = new EntityUI(this.textDrawItemUI, "div", {class: "visibility", onclick: (e) => { main.visibilityAnyObject(this); e.stopPropagation(); }}); 11 | 12 | this.name = name; 13 | this.x = x; 14 | this.y = y; 15 | this.width = width; 16 | this.height = height; 17 | this.margin = margin; 18 | this.padding = padding; 19 | this.rows = rows; 20 | this.columns = columns; 21 | 22 | this.visibility = true; 23 | } 24 | 25 | GuideGrid.prototype.copyGuideGrid = function(guideGrid) 26 | { 27 | guideGrid.internalId = this.internalId; 28 | guideGrid.name = this.name; 29 | guideGrid.x = this.x; 30 | guideGrid.y = this.y; 31 | guideGrid.width = this.width; 32 | guideGrid.height = this.height; 33 | guideGrid.margin = this.margin; 34 | guideGrid.padding = this.padding; 35 | guideGrid.rows = this.rows; 36 | guideGrid.columns = this.columns; 37 | }; 38 | 39 | GuideGrid.prototype.getHorizontalLine = function(idx) 40 | { 41 | return this.y + this.height / this.rows * idx; 42 | }; 43 | 44 | GuideGrid.prototype.getHorizontalLineCount = function() 45 | { 46 | if(this.rows > 0 && this.columns > 0) 47 | return this.rows + 1; 48 | 49 | return 0; 50 | }; 51 | 52 | GuideGrid.prototype.getVerticalLine = function(idx) 53 | { 54 | return this.x + this.width / this.columns * idx; 55 | }; 56 | 57 | GuideGrid.prototype.getVerticalLineCount = function() 58 | { 59 | if(this.rows > 0 && this.columns > 0) 60 | return this.columns + 1; 61 | 62 | return 0; 63 | }; 64 | 65 | GuideGrid.prototype.offsetRect = function(offsetX, offsetY) 66 | { 67 | this.x += offsetX; 68 | this.y += offsetY; 69 | }; 70 | 71 | GuideGrid.prototype.setRectLeft = function(rectLeft) 72 | { 73 | this.width = this.getRectRight() - rectLeft; 74 | this.x = rectLeft; 75 | }; 76 | 77 | GuideGrid.prototype.setRectTop = function(rectTop) 78 | { 79 | this.height = this.getRectBottom() - rectTop; 80 | this.y = rectTop; 81 | }; 82 | 83 | GuideGrid.prototype.setRectRight = function(rectRight) 84 | { 85 | this.width = rectRight - this.x; 86 | }; 87 | 88 | GuideGrid.prototype.setRectBottom = function(rectBottom) 89 | { 90 | this.height = rectBottom - this.y; 91 | }; 92 | 93 | GuideGrid.prototype.getRectLeft = function() 94 | { 95 | return this.x; 96 | }; 97 | 98 | GuideGrid.prototype.getRectTop = function() 99 | { 100 | return this.y; 101 | }; 102 | 103 | GuideGrid.prototype.getRectRight = function() 104 | { 105 | return this.x + this.width; 106 | }; 107 | 108 | GuideGrid.prototype.getRectBottom = function() 109 | { 110 | return this.y + this.height; 111 | }; 112 | 113 | GuideGrid.prototype.setVisibility = function(visibility) 114 | { 115 | this.visibility = visibility; 116 | this.visibilityUI.element.style.backgroundPositionY = visibility ? "0px" : "-24px"; 117 | }; 118 | 119 | GuideGrid.prototype.getMyIndex = function(project) 120 | { 121 | return project.guideGrids.indexOf(this); 122 | }; 123 | 124 | GuideGrid.prototype.historyGuideGridCreate = function(project, funcname, oldValue, newValue) 125 | { 126 | if(funcname == "applyOldValue") 127 | { 128 | project.removeGuideGrid(this); 129 | } 130 | else if(funcname == "updateOldValue") 131 | { 132 | return []; 133 | } 134 | else if(funcname == "updateNewValue") 135 | { 136 | return [this.x, this.y, this.width, this.height, this.margin, this.padding, this.rows, this.columns]; 137 | } 138 | }; 139 | 140 | GuideGrid.prototype.historyGuideGridRemove = function(project, funcname, oldValue, newValue) 141 | { 142 | if(funcname == "applyNewValue") 143 | { 144 | project.removeGuideGrid(this); 145 | } 146 | else if(funcname == "updateOldValue") 147 | { 148 | return [this.name, this.x, this.y, this.width, this.height, this.margin, this.padding, this.rows, this.columns, this.visibility, this.getMyIndex(project)]; 149 | } 150 | else if(funcname == "updateNewValue") 151 | { 152 | return []; 153 | } 154 | }; 155 | 156 | GuideGrid.prototype.historyVisibility = function(project, funcname, oldValue, newValue) 157 | { 158 | if(funcname == "applyOldValue" || funcname == "applyNewValue") 159 | { 160 | this.setVisibility(newValue); 161 | } 162 | else if(funcname == "updateOldValue" || funcname == "updateNewValue") 163 | { 164 | return this.visibility; 165 | } 166 | }; 167 | -------------------------------------------------------------------------------- /assets/js/guideline.js: -------------------------------------------------------------------------------- 1 | 2 | function GuideLine(main, internalId, name, x, y, size, padding, style) 3 | { 4 | this.main = main; 5 | this.internalId = internalId; 6 | 7 | this.textDrawItemUI = new EntityUI(null, "div", {class: "textDrawItem", onclick: (e) => { if(e.shiftKey) { main.adjacentAnyObject(this, e.ctrlKey); } else if(e.ctrlKey) { main.toggleAnyObject(this); } else { main.changeGuideLine(this); } }, contextmenu: (e) => { main.contextMenuGuideLine(this, e.clientX, e.clientY); e.preventDefault(); }}); 8 | this.thumbnailUI = new EntityUI(this.textDrawItemUI, "img", { src: "./assets/images/icon-guide-line.png", width: "24", height: "24", draggable: false }); 9 | this.nameUI = new EntityUI(this.textDrawItemUI, "span", {innerText: name}); 10 | this.visibilityUI = new EntityUI(this.textDrawItemUI, "div", {class: "visibility", onclick: (e) => { main.visibilityAnyObject(this); e.stopPropagation(); }}); 11 | 12 | this.name = name; 13 | this.x = x; 14 | this.y = y; 15 | this.size = size; 16 | this.padding = padding; 17 | this.style = style; 18 | 19 | this.visibility = true; 20 | } 21 | 22 | GuideLine.prototype.copyGuideLine = function(guideLine) 23 | { 24 | guideLine.internalId = this.internalId; 25 | guideLine.name = this.name; 26 | guideLine.x = this.x; 27 | guideLine.y = this.y; 28 | guideLine.size = this.size; 29 | guideLine.padding = this.padding; 30 | guideLine.style = this.style; 31 | }; 32 | 33 | GuideLine.prototype.offsetRect = function(offsetX, offsetY) 34 | { 35 | this.x += offsetX; 36 | this.y += offsetY; 37 | }; 38 | 39 | GuideLine.prototype.setRectLeft = function(rectLeft) 40 | { 41 | if(this.style == 0) 42 | this.size = this.getRectRight() - rectLeft; 43 | 44 | this.x = rectLeft; 45 | }; 46 | 47 | GuideLine.prototype.setRectTop = function(rectTop) 48 | { 49 | if(this.style == 1) 50 | this.size = this.getRectBottom() - rectTop; 51 | 52 | this.y = rectTop; 53 | }; 54 | 55 | GuideLine.prototype.setRectRight = function(rectRight) 56 | { 57 | if(this.style == 0) 58 | this.size = rectRight - this.x; 59 | }; 60 | 61 | GuideLine.prototype.setRectBottom = function(rectBottom) 62 | { 63 | if(this.style == 1) 64 | this.size = rectBottom - this.y; 65 | }; 66 | 67 | GuideLine.prototype.getRectLeft = function() 68 | { 69 | return this.x; 70 | }; 71 | 72 | GuideLine.prototype.getRectTop = function() 73 | { 74 | return this.y; 75 | }; 76 | 77 | GuideLine.prototype.getRectRight = function() 78 | { 79 | if(this.style == 0) 80 | return this.x + this.size; 81 | 82 | return this.x; 83 | }; 84 | 85 | GuideLine.prototype.getRectBottom = function() 86 | { 87 | if(this.style == 1) 88 | return this.y + this.size; 89 | 90 | return this.y; 91 | }; 92 | 93 | GuideLine.prototype.setVisibility = function(visibility) 94 | { 95 | this.visibility = visibility; 96 | this.visibilityUI.element.style.backgroundPositionY = visibility ? "0px" : "-24px"; 97 | }; 98 | 99 | GuideLine.prototype.getMyIndex = function(project) 100 | { 101 | return project.guideLines.indexOf(this); 102 | }; 103 | 104 | GuideLine.prototype.historyGuideLineCreate = function(project, funcname, oldValue, newValue) 105 | { 106 | if(funcname == "applyOldValue") 107 | { 108 | project.removeGuideLine(this); 109 | } 110 | else if(funcname == "updateOldValue") 111 | { 112 | return []; 113 | } 114 | else if(funcname == "updateNewValue") 115 | { 116 | return [this.x, this.y, this.size, this.padding, this.style]; 117 | } 118 | }; 119 | 120 | GuideLine.prototype.historyGuideLineRemove = function(project, funcname, oldValue, newValue) 121 | { 122 | if(funcname == "applyNewValue") 123 | { 124 | project.removeGuideLine(this); 125 | } 126 | else if(funcname == "updateOldValue") 127 | { 128 | return [this.name, this.x, this.y, this.size, this.padding, this.style, this.visibility, this.getMyIndex(project)]; 129 | } 130 | else if(funcname == "updateNewValue") 131 | { 132 | return []; 133 | } 134 | }; 135 | 136 | GuideLine.prototype.historyVisibility = function(project, funcname, oldValue, newValue) 137 | { 138 | if(funcname == "applyOldValue" || funcname == "applyNewValue") 139 | { 140 | this.setVisibility(newValue); 141 | } 142 | else if(funcname == "updateOldValue" || funcname == "updateNewValue") 143 | { 144 | return this.visibility; 145 | } 146 | }; 147 | -------------------------------------------------------------------------------- /assets/js/historydata.js: -------------------------------------------------------------------------------- 1 | 2 | function HistoryData(type, project, anyObject) 3 | { 4 | this.type = type; 5 | 6 | if(anyObject.type !== undefined && anyObject.data !== undefined) 7 | { 8 | this.internalId = anyObject.data[0]; 9 | this.oldValue = anyObject.data[1]; 10 | this.newValue = anyObject.data[2]; 11 | this.selections = anyObject.data[3]; 12 | } 13 | else 14 | { 15 | this.internalId = anyObject.internalId; 16 | this.updateOldValue(project, anyObject); 17 | this.updateNewValue(project, anyObject); 18 | this.selections = []; 19 | } 20 | } 21 | 22 | HistoryData.prototype.copyHistoryData = function(historyData) 23 | { 24 | historyData.type = this.type.id; 25 | historyData.data = [this.internalId, this.oldValue, this.newValue, this.selections]; 26 | }; 27 | 28 | HistoryData.prototype.updateOldValue = function(project, anyObject) 29 | { 30 | this.oldValue = []; 31 | 32 | for(let i = 0; i < this.type.actions.length; i++) 33 | { 34 | let action = this.type.actions[i]; 35 | 36 | if(anyObject[action] instanceof Function) 37 | { 38 | this.oldValue.push(anyObject[action](project, "updateOldValue")); 39 | } 40 | else 41 | { 42 | this.oldValue.push(anyObject[action]); 43 | } 44 | } 45 | }; 46 | 47 | HistoryData.prototype.updateNewValue = function(project, anyObject) 48 | { 49 | this.newValue = []; 50 | 51 | for(let i = 0; i < this.type.actions.length; i++) 52 | { 53 | let action = this.type.actions[i]; 54 | 55 | if(anyObject[action] instanceof Function) 56 | { 57 | this.newValue.push(anyObject[action](project, "updateNewValue")); 58 | } 59 | else 60 | { 61 | this.newValue.push(anyObject[action]); 62 | } 63 | } 64 | }; 65 | 66 | HistoryData.prototype.applyOldValue = function(project) 67 | { 68 | let anyObject = project.findInternalId(this.internalId); 69 | 70 | if(anyObject) 71 | { 72 | for(let i = 0; i < this.type.actions.length; i++) 73 | { 74 | let action = this.type.actions[i]; 75 | 76 | if(anyObject[action] instanceof Function) 77 | { 78 | anyObject[action](project, "applyOldValue", this.newValue[i], this.oldValue[i]); 79 | } 80 | else 81 | { 82 | anyObject[action] = this.oldValue[i]; 83 | } 84 | } 85 | } 86 | else 87 | { 88 | for(let i = 0; i < this.type.actions.length; i++) 89 | { 90 | let action = this.type.actions[i]; 91 | 92 | if(project[action] instanceof Function) 93 | { 94 | project[action](this.internalId, "applyOldValue", this.newValue[i], this.oldValue[i]); 95 | } 96 | } 97 | } 98 | }; 99 | 100 | HistoryData.prototype.applyNewValue = function(project) 101 | { 102 | let anyObject = project.findInternalId(this.internalId); 103 | 104 | if(anyObject) 105 | { 106 | for(let i = 0; i < this.type.actions.length; i++) 107 | { 108 | let action = this.type.actions[i]; 109 | 110 | if(anyObject[action] instanceof Function) 111 | { 112 | anyObject[action](project, "applyNewValue", this.oldValue[i], this.newValue[i]); 113 | } 114 | else 115 | { 116 | anyObject[action] = this.newValue[i]; 117 | } 118 | } 119 | } 120 | else 121 | { 122 | for(let i = 0; i < this.type.actions.length; i++) 123 | { 124 | let action = this.type.actions[i]; 125 | 126 | if(project[action] instanceof Function) 127 | { 128 | project[action](this.internalId, "applyNewValue", this.oldValue[i], this.newValue[i]); 129 | } 130 | } 131 | } 132 | }; 133 | 134 | HistoryData.prototype.isValueChanged = function() 135 | { 136 | function isChanged(value1, value2) 137 | { 138 | if(value1 instanceof Array) 139 | { 140 | if(value1.length != value2.length) 141 | return true; 142 | 143 | for(idx in value1) 144 | { 145 | if(isChanged(value1[idx], value2[idx])) 146 | return true; 147 | } 148 | 149 | return false; 150 | } 151 | else 152 | { 153 | return value1 !== value2; 154 | } 155 | } 156 | 157 | return isChanged(this.oldValue, this.newValue); 158 | }; 159 | -------------------------------------------------------------------------------- /assets/js/historytype.js: -------------------------------------------------------------------------------- 1 | 2 | const HistoryType = 3 | { 4 | Beginning: {id: 0, name: "Beginning", actions: []}, 5 | 6 | ProjectOpen: {id: 1, name: "Project Open", actions: ["historyProjectOpen"]}, 7 | ProjectImport: {id: 2, name: "Project Import", actions: ["historyProjectOpen"]}, 8 | 9 | TextDrawCreate: {id: 3, name: "TextDraw Create", actions: ["historyTextDrawCreate"]}, 10 | TextDrawDuplicate: {id: 4, name: "TextDraw Duplicate", actions: ["historyTextDrawDuplicate"]}, 11 | TextDrawFromAnotherPoject: {id: 5, name: "TextDraw Duplicate *", actions: ["historyTextDrawFromAnotherPoject"]}, 12 | TextDrawRemove: {id: 6, name: "TextDraw Remove", actions: ["historyTextDrawRemove"]}, 13 | TextDrawSort: {id: 7, name: "TextDraw Sort", actions: ["historyTextDrawSort"]}, 14 | TextDrawName: {id: 8, name: "TextDraw Name", actions: ["name"]}, 15 | TextDrawText: {id: 9, name: "TextDraw Text", actions: ["text"]}, 16 | TextDrawPosition: {id: 10, name: "TextDraw Position", actions: ["x", "y"]}, 17 | TextDrawLetterSize: {id: 11, name: "TextDraw Letter Size", actions: ["letterSizeX", "letterSizeY"]}, 18 | TextDrawTextSize: {id: 12, name: "TextDraw Text Size", actions: ["textSizeX", "textSizeY"]}, 19 | TextDrawAlignment: {id: 13, name: "TextDraw Alignment", actions: ["historyAlignment"]}, 20 | TextDrawColor: {id: 14, name: "TextDraw Color", actions: ["color"]}, 21 | TextDrawUseBox: {id: 15, name: "TextDraw Use Box", actions: ["useBox"]}, 22 | TextDrawBoxColor: {id: 16, name: "TextDraw Box Color", actions: ["boxColor"]}, 23 | TextDrawSetShadow: {id: 17, name: "TextDraw Set Shadow", actions: ["setShadow"]}, 24 | TextDrawSetOutline: {id: 18, name: "TextDraw Set Outline", actions: ["setOutline"]}, 25 | TextDrawBackgroundColor: {id: 19, name: "TextDraw Background Color", actions: ["backgroundColor"]}, 26 | TextDrawFont: {id: 20, name: "TextDraw Font", actions: ["historyFont"]}, 27 | TextDrawSetProportional: {id: 21, name: "TextDraw Set Proportional", actions: ["setProportional"]}, 28 | TextDrawVisibility: {id: 22, name: "TextDraw Visibility", actions: ["historyVisibility"]}, 29 | TextDrawMove: {id: 23, name: "TextDraw Move", actions: ["x", "y", "textSizeX", "textSizeY"]}, 30 | TextDrawResize: {id: 24, name: "TextDraw Resize", actions: ["x", "y", "textSizeX", "textSizeY"]}, 31 | TextDrawResizeLetter: {id: 25, name: "TextDraw Resize Letter", actions: ["x", "y", "textSizeX", "textSizeY", "letterSizeX", "letterSizeY"]}, 32 | 33 | GuideGridCreate: {id: 26, name: "GuideGrid Create", actions: ["historyGuideGridCreate"]}, 34 | GuideGridDuplicate: {id: 27, name: "GuideGrid Duplicate", actions: ["historyGuideGridCreate"]}, 35 | GuideGridFromAnotherPoject: {id: 28, name: "GuideGrid Duplicate *", actions: ["historyGuideGridCreate"]}, 36 | GuideGridRemove: {id: 29, name: "GuideGrid Remove", actions: ["historyGuideGridRemove"]}, 37 | GuideGridSort: {id: 30, name: "GuideGrid Sort", actions: ["historyGuideGridSort"]}, 38 | GuideGridName: {id: 31, name: "GuideGrid Name", actions: ["name"]}, 39 | GuideGridPosition: {id: 32, name: "GuideGrid Position", actions: ["x", "y"]}, 40 | GuideGridSize: {id: 33, name: "GuideGrid Size", actions: ["width", "height"]}, 41 | GuideGridMargin: {id: 34, name: "GuideGrid Margin", actions: ["margin"]}, 42 | GuideGridPadding: {id: 35, name: "GuideGrid Padding", actions: ["padding"]}, 43 | GuideGridRows: {id: 36, name: "GuideGrid Rows", actions: ["rows"]}, 44 | GuideGridColumns: {id: 37, name: "GuideGrid Columns", actions: ["columns"]}, 45 | GuideGridVisibility: {id: 38, name: "GuideGrid Visibility", actions: ["historyVisibility"]}, 46 | GuideGridMove: {id: 39, name: "GuideGrid Move", actions: ["x", "y"]}, 47 | GuideGridResize: {id: 40, name: "GuideGrid Resize", actions: ["x", "y", "width", "height"]}, 48 | 49 | GuideLineCreate: {id: 41, name: "GuideLine Create", actions: ["historyGuideLineCreate"]}, 50 | GuideLineDuplicate: {id: 42, name: "GuideLine Duplicate", actions: ["historyGuideLineCreate"]}, 51 | GuideLineFromAnotherPoject: {id: 43, name: "GuideLine Duplicate *", actions: ["historyGuideLineCreate"]}, 52 | GuideLineRemove: {id: 44, name: "GuideLine Remove", actions: ["historyGuideLineRemove"]}, 53 | GuideLineSort: {id: 45, name: "GuideLine Sort", actions: ["historyGuideLineSort"]}, 54 | GuideLineName: {id: 46, name: "GuideLine Name", actions: ["name"]}, 55 | GuideLinePosition: {id: 47, name: "GuideLine Position", actions: ["x", "y"]}, 56 | GuideLineSize: {id: 48, name: "GuideLine Size", actions: ["size"]}, 57 | GuideLinePadding: {id: 49, name: "GuideLine Padding", actions: ["padding"]}, 58 | GuideLineStyle: {id: 50, name: "GuideLine Style", actions: ["style"]}, 59 | GuideLineVisibility: {id: 51, name: "GuideLine Visibility", actions: ["historyVisibility"]}, 60 | GuideLineMove: {id: 52, name: "GuideLine Move", actions: ["x", "y"]}, 61 | GuideLineResize: {id: 53, name: "GuideLine Resize", actions: ["x", "y", "size"]}, 62 | 63 | MultipleDuplicate: {id: 54, name: "Multiple Duplicate", actions: ["historyMultipleDuplicate", "historyRect"]}, 64 | MultipleFromAnotherPoject: {id: 55, name: "Multiple Duplicate *", actions: ["historyMultipleFromAnotherPoject", "historyRect"]}, 65 | MultipleRemove: {id: 56, name: "Multiple Remove", actions: ["historyMultipleRemove", "historyRect"]}, 66 | MultiplePosition: {id: 57, name: "Multiple Position", actions: ["historyRect"], setSelections: true}, 67 | MultipleSize: {id: 58, name: "Multiple Size", actions: ["historyRect"], setSelections: true}, 68 | MultipleMove: {id: 59, name: "Multiple Move", actions: ["historyRect"], setSelections: true}, 69 | MultipleResize: {id: 60, name: "Multiple Resize", actions: ["historyRect"], setSelections: true}, 70 | }; 71 | 72 | const HistoryTypeById = Object.values(HistoryType); 73 | 74 | for(id in HistoryTypeById) 75 | { 76 | if(HistoryTypeById[id].id != id) 77 | console.error("HistoryTypeById[" + id + "].id(" + HistoryTypeById[id].id + ") != id(" + id + ")"); 78 | } 79 | -------------------------------------------------------------------------------- /assets/js/multipleselection.js: -------------------------------------------------------------------------------- 1 | 2 | function MultipleSelection(main) 3 | { 4 | this.main = main; 5 | this.internalId = 0; 6 | 7 | this.rectLeft = 0; 8 | this.rectTop = 0; 9 | this.rectRight = 0; 10 | this.rectBottom = 0; 11 | 12 | this.selections = []; 13 | this.selectionLast = null; 14 | } 15 | 16 | MultipleSelection.prototype.isSelected = function(anyObject) 17 | { 18 | if(anyObject) 19 | { 20 | for(let i = 0; i < this.selections.length; i++) 21 | { 22 | if(this.selections[i] == anyObject) 23 | return true; 24 | } 25 | } 26 | 27 | return false; 28 | }; 29 | 30 | MultipleSelection.prototype.addSelection = function(anyObject) 31 | { 32 | if(anyObject) 33 | { 34 | this.selections.push(anyObject); 35 | 36 | if(this.selections.length != 1) 37 | this.recalculateSize(); 38 | } 39 | }; 40 | 41 | MultipleSelection.prototype.removeSelection = function(anyObject) 42 | { 43 | if(anyObject) 44 | { 45 | for(let i = 0; i < this.selections.length; i++) 46 | { 47 | if(this.selections[i] == anyObject) 48 | { 49 | this.selections.splice(i, 1); 50 | break; 51 | } 52 | } 53 | 54 | if(this.selections.length != 1) 55 | this.recalculateSize(); 56 | } 57 | }; 58 | 59 | MultipleSelection.prototype.getCurrentTextDraw = function() 60 | { 61 | let anyObject = this.getCurrentAnyObject(); 62 | 63 | if(anyObject instanceof TextDraw) 64 | return anyObject; 65 | 66 | return null; 67 | }; 68 | 69 | MultipleSelection.prototype.getCurrentGuideGrid = function() 70 | { 71 | let anyObject = this.getCurrentAnyObject(); 72 | 73 | if(anyObject instanceof GuideGrid) 74 | return anyObject; 75 | 76 | return null; 77 | }; 78 | 79 | MultipleSelection.prototype.getCurrentGuideLine = function() 80 | { 81 | let anyObject = this.getCurrentAnyObject(); 82 | 83 | if(anyObject instanceof GuideLine) 84 | return anyObject; 85 | 86 | return null; 87 | }; 88 | 89 | MultipleSelection.prototype.getCurrentAnyObject = function() 90 | { 91 | if(this.selections.length != 0) 92 | return this.selections.length == 1 ? this.selections[0] : this; 93 | 94 | return null; 95 | }; 96 | 97 | MultipleSelection.prototype.recalculateSize = function() 98 | { 99 | this.rectLeft = 0; 100 | this.rectTop = 0; 101 | this.rectRight = 0; 102 | this.rectBottom = 0; 103 | 104 | for(let i = 0; i < this.selections.length; i++) 105 | { 106 | let rectLeft = this.selections[i].getRectLeft(); 107 | let rectTop = this.selections[i].getRectTop(); 108 | let rectRight = this.selections[i].getRectRight(); 109 | let rectBottom = this.selections[i].getRectBottom(); 110 | 111 | if(rectLeft < rectRight) 112 | { 113 | if(i == 0 || rectLeft < this.rectLeft) 114 | this.rectLeft = rectLeft; 115 | 116 | if(i == 0 || rectRight > this.rectRight) 117 | this.rectRight = rectRight; 118 | } 119 | else 120 | { 121 | if(i == 0 || rectRight < this.rectLeft) 122 | this.rectLeft = rectRight; 123 | 124 | if(i == 0 || rectLeft > this.rectRight) 125 | this.rectRight = rectLeft; 126 | } 127 | 128 | if(rectTop < rectBottom) 129 | { 130 | if(i == 0 || rectTop < this.rectTop) 131 | this.rectTop = rectTop; 132 | 133 | if(i == 0 || rectBottom > this.rectBottom) 134 | this.rectBottom = rectBottom; 135 | } 136 | else 137 | { 138 | if(i == 0 || rectBottom < this.rectTop) 139 | this.rectTop = rectBottom; 140 | 141 | if(i == 0 || rectTop > this.rectBottom) 142 | this.rectBottom = rectTop; 143 | } 144 | } 145 | 146 | for(let i = 0; i < this.selections.length; i++) 147 | { 148 | this.selections[i].percentLeft = this.selections[i].getRectLeft().getPercentOf(this.rectLeft, this.rectRight); 149 | this.selections[i].percentTop = this.selections[i].getRectTop().getPercentOf(this.rectTop, this.rectBottom); 150 | this.selections[i].percentRight = this.selections[i].getRectRight().getPercentOf(this.rectLeft, this.rectRight); 151 | this.selections[i].percentBottom = this.selections[i].getRectBottom().getPercentOf(this.rectTop, this.rectBottom); 152 | 153 | this.selections[i].oldLetterSizeX = this.selections[i].letterSizeX; 154 | this.selections[i].oldLetterSizeY = this.selections[i].letterSizeY; 155 | this.selections[i].oldWidth = this.selections[i].getRectRight() - this.selections[i].getRectLeft(); 156 | this.selections[i].oldHeight = this.selections[i].getRectBottom() - this.selections[i].getRectTop(); 157 | } 158 | }; 159 | 160 | MultipleSelection.prototype.offsetRect = function(offsetX, offsetY) 161 | { 162 | if(this.selections.length == 1) 163 | return this.selections[0].offsetRect(offsetX, offsetY); 164 | 165 | this.rectLeft += offsetX; 166 | this.rectRight += offsetX; 167 | this.rectTop += offsetY; 168 | this.rectBottom += offsetY; 169 | 170 | for(let i = 0; i < this.selections.length; i++) 171 | { 172 | this.selections[i].offsetRect(offsetX, offsetY); 173 | } 174 | }; 175 | 176 | MultipleSelection.prototype.setRectLeft = function(rectLeft) 177 | { 178 | if(this.selections.length == 1) 179 | return this.selections[0].setRectLeft(rectLeft); 180 | 181 | this.rectLeft = rectLeft; 182 | 183 | let width = this.getWidth(); 184 | 185 | if(width == 0) 186 | width = 0.0000009; 187 | 188 | for(let i = 0; i < this.selections.length; i++) 189 | { 190 | this.selections[i].setRectLeft(this.rectLeft + this.selections[i].percentLeft / 100 * width); 191 | this.selections[i].setRectRight(this.rectLeft + this.selections[i].percentRight / 100 * width); 192 | 193 | let newWidth = this.selections[i].getRectRight() - this.selections[i].getRectLeft(); 194 | 195 | if(this.main.letterSizeOnResize && this.selections[i] instanceof TextDraw) 196 | { 197 | if(this.selections[i].oldLetterSizeX != 0) 198 | { 199 | this.selections[i].letterSizeX = newWidth.getPercentOf(0, this.selections[i].oldWidth) / 100 * this.selections[i].oldLetterSizeX; 200 | } 201 | else 202 | { 203 | this.selections[i].letterSizeX = 0; 204 | } 205 | } 206 | } 207 | }; 208 | 209 | MultipleSelection.prototype.setRectTop = function(rectTop) 210 | { 211 | if(this.selections.length == 1) 212 | return this.selections[0].setRectTop(rectTop); 213 | 214 | this.rectTop = rectTop; 215 | 216 | let height = this.getHeight(); 217 | 218 | if(height == 0) 219 | height = 0.0000009; 220 | 221 | for(let i = 0; i < this.selections.length; i++) 222 | { 223 | this.selections[i].setRectTop(this.rectTop + this.selections[i].percentTop / 100 * height); 224 | this.selections[i].setRectBottom(this.rectTop + this.selections[i].percentBottom / 100 * height); 225 | 226 | let newHeight = this.selections[i].getRectBottom() - this.selections[i].getRectTop(); 227 | 228 | if(this.main.letterSizeOnResize && this.selections[i] instanceof TextDraw) 229 | { 230 | if(this.selections[i].oldLetterSizeY != 0) 231 | { 232 | this.selections[i].letterSizeY = newHeight.getPercentOf(0, this.selections[i].oldHeight) / 100 * this.selections[i].oldLetterSizeY; 233 | } 234 | else 235 | { 236 | this.selections[i].letterSizeY = 0; 237 | } 238 | } 239 | } 240 | }; 241 | 242 | MultipleSelection.prototype.setRectRight = function(rectRight) 243 | { 244 | if(this.selections.length == 1) 245 | return this.selections[0].setRectRight(rectRight); 246 | 247 | this.rectRight = rectRight; 248 | 249 | let width = this.getWidth(); 250 | 251 | if(width == 0) 252 | width = 0.0000009; 253 | 254 | for(let i = 0; i < this.selections.length; i++) 255 | { 256 | this.selections[i].setRectLeft(this.rectLeft + this.selections[i].percentLeft / 100 * width); 257 | this.selections[i].setRectRight(this.rectLeft + this.selections[i].percentRight / 100 * width); 258 | 259 | let newWidth = this.selections[i].getRectRight() - this.selections[i].getRectLeft(); 260 | 261 | if(this.main.letterSizeOnResize && this.selections[i] instanceof TextDraw) 262 | { 263 | if(this.selections[i].oldLetterSizeX != 0) 264 | { 265 | this.selections[i].letterSizeX = newWidth.getPercentOf(0, this.selections[i].oldWidth) / 100 * this.selections[i].oldLetterSizeX; 266 | } 267 | else 268 | { 269 | this.selections[i].letterSizeX = 0; 270 | } 271 | } 272 | } 273 | }; 274 | 275 | MultipleSelection.prototype.setRectBottom = function(rectBottom) 276 | { 277 | if(this.selections.length == 1) 278 | return this.selections[0].setRectBottom(rectBottom); 279 | 280 | this.rectBottom = rectBottom; 281 | 282 | let height = this.getHeight(); 283 | 284 | if(height == 0) 285 | height = 0.0000009; 286 | 287 | for(let i = 0; i < this.selections.length; i++) 288 | { 289 | this.selections[i].setRectTop(this.rectTop + this.selections[i].percentTop / 100 * height); 290 | this.selections[i].setRectBottom(this.rectTop + this.selections[i].percentBottom / 100 * height); 291 | 292 | let newHeight = this.selections[i].getRectBottom() - this.selections[i].getRectTop(); 293 | 294 | if(this.main.letterSizeOnResize && this.selections[i] instanceof TextDraw) 295 | { 296 | if(this.selections[i].oldLetterSizeY != 0) 297 | { 298 | this.selections[i].letterSizeY = newHeight.getPercentOf(0, this.selections[i].oldHeight) / 100 * this.selections[i].oldLetterSizeY; 299 | } 300 | else 301 | { 302 | this.selections[i].letterSizeY = 0; 303 | } 304 | } 305 | } 306 | }; 307 | 308 | MultipleSelection.prototype.getRectLeft = function() 309 | { 310 | if(this.selections.length == 1) 311 | return this.selections[0].getRectLeft(); 312 | 313 | return this.rectLeft; 314 | }; 315 | 316 | MultipleSelection.prototype.getRectTop = function() 317 | { 318 | if(this.selections.length == 1) 319 | return this.selections[0].getRectTop(); 320 | 321 | return this.rectTop; 322 | }; 323 | 324 | MultipleSelection.prototype.getRectRight = function() 325 | { 326 | if(this.selections.length == 1) 327 | return this.selections[0].getRectRight(); 328 | 329 | return this.rectRight; 330 | }; 331 | 332 | MultipleSelection.prototype.getRectBottom = function() 333 | { 334 | if(this.selections.length == 1) 335 | return this.selections[0].getRectBottom(); 336 | 337 | return this.rectBottom; 338 | }; 339 | 340 | MultipleSelection.prototype.setX = function(x) 341 | { 342 | let width = this.getWidth(); 343 | 344 | this.setRectLeft(x); 345 | this.setRectRight(x + width); 346 | }; 347 | 348 | MultipleSelection.prototype.setY = function(y) 349 | { 350 | let height = this.getHeight(); 351 | 352 | this.setRectTop(y); 353 | this.setRectBottom(y + height); 354 | }; 355 | 356 | MultipleSelection.prototype.setWidth = function(width) 357 | { 358 | this.setRectRight(this.getRectLeft() + width); 359 | }; 360 | 361 | MultipleSelection.prototype.setHeight = function(height) 362 | { 363 | this.setRectBottom(this.getRectTop() + height); 364 | }; 365 | 366 | MultipleSelection.prototype.getX = function() 367 | { 368 | return this.getRectLeft(); 369 | }; 370 | 371 | MultipleSelection.prototype.getY = function() 372 | { 373 | return this.getRectTop(); 374 | }; 375 | 376 | MultipleSelection.prototype.getWidth = function() 377 | { 378 | return this.getRectRight() - this.getRectLeft(); 379 | }; 380 | 381 | MultipleSelection.prototype.getHeight = function() 382 | { 383 | return this.getRectBottom() - this.getRectTop(); 384 | }; 385 | 386 | MultipleSelection.prototype.getMyIndex = function(project) 387 | { 388 | if(this.selections.length == 1) 389 | return this.selections[0].getMyIndex(project); 390 | 391 | let indices = []; 392 | 393 | for(let i = 0; i < this.selections.length; i++) 394 | { 395 | indices.push(this.selections[i].getMyIndex(project)); 396 | } 397 | 398 | return indices; 399 | }; 400 | 401 | MultipleSelection.prototype.historyProjectOpen = function(project, funcname, oldValue, newValue) 402 | { 403 | if(funcname == "applyOldValue") 404 | { 405 | let textDraws = oldValue[0]; 406 | let guideGrids = oldValue[1]; 407 | let guideLines = oldValue[2]; 408 | 409 | for(let i = 0; i < textDraws.length; i++) 410 | { 411 | let textDraw = project.findInternalId(textDraws[i][0]); 412 | 413 | if(textDraw) 414 | { 415 | project.removeTextDraw(textDraw); 416 | } 417 | } 418 | 419 | for(let i = 0; i < guideGrids.length; i++) 420 | { 421 | let guideGrid = project.findInternalId(guideGrids[i][0]); 422 | 423 | if(guideGrid) 424 | { 425 | project.removeGuideGrid(guideGrid); 426 | } 427 | } 428 | 429 | for(let i = 0; i < guideLines.length; i++) 430 | { 431 | let guideLine = project.findInternalId(guideLines[i][0]); 432 | 433 | if(guideLine) 434 | { 435 | project.removeGuideLine(guideLine); 436 | } 437 | } 438 | } 439 | else if(funcname == "applyNewValue") 440 | { 441 | let textDraws = newValue[0]; 442 | let guideGrids = newValue[1]; 443 | let guideLines = newValue[2]; 444 | 445 | for(let i = 0; i < textDraws.length; i++) 446 | { 447 | let textDraw = new TextDraw(project.main, textDraws[i][0], textDraws[i][1], textDraws[i][2], textDraws[i][3], textDraws[i][4]); 448 | 449 | textDraw.letterSizeX = textDraws[i][5]; 450 | textDraw.letterSizeY = textDraws[i][6]; 451 | textDraw.textSizeX = textDraws[i][7]; 452 | textDraw.textSizeY = textDraws[i][8]; 453 | textDraw.alignment = textDraws[i][9]; 454 | textDraw.color = textDraws[i][10]; 455 | textDraw.useBox = textDraws[i][11]; 456 | textDraw.boxColor = textDraws[i][12]; 457 | textDraw.setShadow = textDraws[i][13]; 458 | textDraw.setOutline = textDraws[i][14]; 459 | textDraw.backgroundColor = textDraws[i][15]; 460 | textDraw.font = textDraws[i][16]; 461 | textDraw.setProportional = textDraws[i][17]; 462 | textDraw.setVisibility(textDraws[i][18]); 463 | 464 | project.textDrawList.splice(textDraws[i][19], 0, textDraw); 465 | } 466 | 467 | for(let i = 0; i < guideGrids.length; i++) 468 | { 469 | let guideGrid = new GuideGrid(project.main, guideGrids[i][0], guideGrids[i][1], guideGrids[i][2], guideGrids[i][3], guideGrids[i][4], guideGrids[i][5], guideGrids[i][6], guideGrids[i][7], guideGrids[i][8], guideGrids[i][9]); 470 | guideGrid.setVisibility(guideGrids[i][10]); 471 | project.guideGrids.splice(guideGrids[i][11], 0, guideGrid); 472 | } 473 | 474 | for(let i = 0; i < guideLines.length; i++) 475 | { 476 | let guideLine = new GuideLine(project.main, guideLines[i][0], guideLines[i][1], guideLines[i][2], guideLines[i][3], guideLines[i][4], guideLines[i][5], guideLines[i][6]); 477 | guideLine.setVisibility(guideLines[i][7]); 478 | project.guideLines.splice(guideLines[i][8], 0, guideLine); 479 | } 480 | } 481 | else if(funcname == "updateOldValue") 482 | { 483 | return []; 484 | } 485 | else if(funcname == "updateNewValue") 486 | { 487 | let lastLoad = project.lastLoad; 488 | 489 | if(!lastLoad) 490 | lastLoad = this.selections; 491 | 492 | let textDraws = []; 493 | let guideGrids = []; 494 | let guideLines = []; 495 | 496 | for(let i = 0; i < lastLoad.length; i++) 497 | { 498 | let anyObject = lastLoad[i]; 499 | 500 | if(anyObject instanceof TextDraw) 501 | { 502 | textDraws.push([anyObject.internalId, anyObject.name, anyObject.text, anyObject.x, anyObject.y, anyObject.letterSizeX, anyObject.letterSizeY, anyObject.textSizeX, anyObject.textSizeY, anyObject.alignment, anyObject.color, anyObject.useBox, anyObject.boxColor, anyObject.setShadow, anyObject.setOutline, anyObject.backgroundColor, anyObject.font, anyObject.setProportional, anyObject.visibility, anyObject.getMyIndex(project)]); 503 | } 504 | else if(anyObject instanceof GuideGrid) 505 | { 506 | guideGrids.push([anyObject.internalId, anyObject.name, anyObject.x, anyObject.y, anyObject.width, anyObject.height, anyObject.margin, anyObject.padding, anyObject.rows, anyObject.columns, anyObject.visibility, anyObject.getMyIndex(project)]); 507 | } 508 | else if(anyObject instanceof GuideLine) 509 | { 510 | guideLines.push([anyObject.internalId, anyObject.name, anyObject.x, anyObject.y, anyObject.size, anyObject.padding, anyObject.style, anyObject.visibility, anyObject.getMyIndex(project)]); 511 | } 512 | } 513 | 514 | return [textDraws, guideGrids, guideLines]; 515 | } 516 | }; 517 | 518 | MultipleSelection.prototype.historyMultipleDuplicate = function(project, funcname, oldValue, newValue) 519 | { 520 | if(funcname == "applyOldValue") 521 | { 522 | let textDraws = oldValue[0]; 523 | let guideGrids = oldValue[1]; 524 | let guideLines = oldValue[2]; 525 | 526 | for(let i = 0; i < textDraws.length; i++) 527 | { 528 | let textDraw = project.findInternalId(textDraws[i][0]); 529 | 530 | if(textDraw) 531 | { 532 | project.removeTextDraw(textDraw); 533 | } 534 | } 535 | 536 | for(let i = 0; i < guideGrids.length; i++) 537 | { 538 | let guideGrid = project.findInternalId(guideGrids[i][0]); 539 | 540 | if(guideGrid) 541 | { 542 | project.removeGuideGrid(guideGrid); 543 | } 544 | } 545 | 546 | for(let i = 0; i < guideLines.length; i++) 547 | { 548 | let guideLine = project.findInternalId(guideLines[i][0]); 549 | 550 | if(guideLine) 551 | { 552 | project.removeGuideLine(guideLine); 553 | } 554 | } 555 | } 556 | else if(funcname == "applyNewValue") 557 | { 558 | let textDraws = newValue[0]; 559 | let guideGrids = newValue[1]; 560 | let guideLines = newValue[2]; 561 | 562 | this.selections = []; 563 | this.selectionLast = null; 564 | 565 | for(let i = 0; i < textDraws.length; i++) 566 | { 567 | let fromTextDraw = project.findInternalId(textDraws[i][1]); 568 | 569 | if(fromTextDraw) 570 | { 571 | let copiedTextDraw = {}; 572 | fromTextDraw.copyTextDraw(copiedTextDraw); 573 | copiedTextDraw.width = fromTextDraw.getRectRight() - fromTextDraw.getRectLeft(); 574 | copiedTextDraw.height = fromTextDraw.getRectBottom() - fromTextDraw.getRectTop(); 575 | 576 | let textDraw = new TextDraw(project.main, textDraws[i][0], project.getNewName("TextDraw", project.textDrawList), copiedTextDraw.text, copiedTextDraw.x, copiedTextDraw.y); 577 | textDraw.fromTextDraw(copiedTextDraw); 578 | project.textDrawList.push(textDraw); 579 | 580 | this.addSelection(textDraw); 581 | this.selectionLast = textDraw; 582 | } 583 | } 584 | 585 | for(let i = 0; i < guideGrids.length; i++) 586 | { 587 | let fromGuideGrid = project.findInternalId(guideGrids[i][1]); 588 | 589 | if(fromGuideGrid) 590 | { 591 | let guideGrid = new GuideGrid(project.main, guideGrids[i][0], project.getNewName("GuideGrid", project.guideGrids), fromGuideGrid.x, fromGuideGrid.y, fromGuideGrid.width, fromGuideGrid.height, fromGuideGrid.margin, fromGuideGrid.padding, fromGuideGrid.rows, fromGuideGrid.columns); 592 | project.guideGrids.push(guideGrid); 593 | 594 | this.addSelection(guideGrid); 595 | this.selectionLast = guideGrid; 596 | } 597 | } 598 | 599 | for(let i = 0; i < guideLines.length; i++) 600 | { 601 | let fromGuideLine = project.findInternalId(guideLines[i][1]); 602 | 603 | if(fromGuideLine) 604 | { 605 | let guideLine = new GuideLine(project.main, guideLines[i][0], project.getNewName("GuideLine", project.guideLines), fromGuideLine.x, fromGuideLine.y, fromGuideLine.size, fromGuideLine.padding, fromGuideLine.style); 606 | project.guideLines.push(guideLine); 607 | 608 | this.addSelection(guideLine); 609 | this.selectionLast = guideLine; 610 | } 611 | } 612 | } 613 | else if(funcname == "updateOldValue") 614 | { 615 | return []; 616 | } 617 | else if(funcname == "updateNewValue") 618 | { 619 | let textDraws = []; 620 | let guideGrids = []; 621 | let guideLines = []; 622 | 623 | for(let i = 0; i < this.selections.length; i++) 624 | { 625 | let anyObject = this.selections[i]; 626 | 627 | if(anyObject instanceof TextDraw) 628 | { 629 | textDraws.push([anyObject.internalId, anyObject.duplicateFromInternalId]); 630 | } 631 | else if(anyObject instanceof GuideGrid) 632 | { 633 | guideGrids.push([anyObject.internalId, anyObject.duplicateFromInternalId]); 634 | } 635 | else if(anyObject instanceof GuideLine) 636 | { 637 | guideLines.push([anyObject.internalId, anyObject.duplicateFromInternalId]); 638 | } 639 | } 640 | 641 | return [textDraws, guideGrids, guideLines]; 642 | } 643 | }; 644 | 645 | MultipleSelection.prototype.historyMultipleFromAnotherPoject = function(project, funcname, oldValue, newValue) 646 | { 647 | if(funcname == "applyOldValue") 648 | { 649 | let textDraws = oldValue[0]; 650 | let guideGrids = oldValue[1]; 651 | let guideLines = oldValue[2]; 652 | 653 | for(let i = 0; i < textDraws.length; i++) 654 | { 655 | let textDraw = project.findInternalId(textDraws[i][0]); 656 | 657 | if(textDraw) 658 | { 659 | project.removeTextDraw(textDraw); 660 | } 661 | } 662 | 663 | for(let i = 0; i < guideGrids.length; i++) 664 | { 665 | let guideGrid = project.findInternalId(guideGrids[i][0]); 666 | 667 | if(guideGrid) 668 | { 669 | project.removeGuideGrid(guideGrid); 670 | } 671 | } 672 | 673 | for(let i = 0; i < guideLines.length; i++) 674 | { 675 | let guideLine = project.findInternalId(guideLines[i][0]); 676 | 677 | if(guideLine) 678 | { 679 | project.removeGuideLine(guideLine); 680 | } 681 | } 682 | } 683 | else if(funcname == "applyNewValue") 684 | { 685 | let textDraws = newValue[0]; 686 | let guideGrids = newValue[1]; 687 | let guideLines = newValue[2]; 688 | 689 | this.selections = []; 690 | this.selectionLast = null; 691 | 692 | for(let i = 0; i < textDraws.length; i++) 693 | { 694 | let textDraw = new TextDraw(this.main, textDraws[i][0], project.getNewName("TextDraw", project.textDrawList), textDraws[i][1], textDraws[i][2], textDraws[i][3]); 695 | 696 | textDraw.letterSizeX = textDraws[i][4]; 697 | textDraw.letterSizeY = textDraws[i][5]; 698 | textDraw.textSizeX = textDraws[i][6]; 699 | textDraw.textSizeY = textDraws[i][7]; 700 | textDraw.alignment = textDraws[i][8]; 701 | textDraw.color = textDraws[i][9]; 702 | textDraw.useBox = textDraws[i][10]; 703 | textDraw.boxColor = textDraws[i][11]; 704 | textDraw.setShadow = textDraws[i][12]; 705 | textDraw.setOutline = textDraws[i][13]; 706 | textDraw.backgroundColor = textDraws[i][14]; 707 | textDraw.font = textDraws[i][15]; 708 | textDraw.setProportional = textDraws[i][16]; 709 | 710 | project.textDrawList.push(textDraw); 711 | 712 | this.addSelection(textDraw); 713 | this.selectionLast = textDraw; 714 | } 715 | 716 | for(let i = 0; i < guideGrids.length; i++) 717 | { 718 | let guideGrid = new GuideGrid(project.main, guideGrids[i][0], project.getNewName("GuideGrid", project.guideGrids), guideGrids[i][1], guideGrids[i][2], guideGrids[i][3], guideGrids[i][4], guideGrids[i][5], guideGrids[i][6], guideGrids[i][7], guideGrids[i][8]); 719 | project.guideGrids.push(guideGrid); 720 | 721 | this.addSelection(guideGrid); 722 | this.selectionLast = guideGrid; 723 | } 724 | 725 | for(let i = 0; i < guideLines.length; i++) 726 | { 727 | let guideLine = new GuideLine(project.main, guideLines[i][0], project.getNewName("GuideLine", project.guideLines), guideLines[i][1], guideLines[i][2], guideLines[i][3], guideLines[i][4], guideLines[i][5]); 728 | project.guideLines.push(guideLine); 729 | 730 | this.addSelection(guideLine); 731 | this.selectionLast = guideLine; 732 | } 733 | } 734 | else if(funcname == "updateOldValue") 735 | { 736 | return []; 737 | } 738 | else if(funcname == "updateNewValue") 739 | { 740 | let textDraws = []; 741 | let guideGrids = []; 742 | let guideLines = []; 743 | 744 | for(let i = 0; i < this.selections.length; i++) 745 | { 746 | let anyObject = this.selections[i]; 747 | 748 | if(anyObject instanceof TextDraw) 749 | { 750 | textDraws.push([anyObject.internalId, anyObject.text, anyObject.x, anyObject.y, anyObject.letterSizeX, anyObject.letterSizeY, anyObject.textSizeX, anyObject.textSizeY, anyObject.alignment, anyObject.color, anyObject.useBox, anyObject.boxColor, anyObject.setShadow, anyObject.setOutline, anyObject.backgroundColor, anyObject.font, anyObject.setProportional]); 751 | } 752 | else if(anyObject instanceof GuideGrid) 753 | { 754 | guideGrids.push([anyObject.internalId, anyObject.x, anyObject.y, anyObject.width, anyObject.height, anyObject.margin, anyObject.padding, anyObject.rows, anyObject.columns]); 755 | } 756 | else if(anyObject instanceof GuideLine) 757 | { 758 | guideLines.push([anyObject.internalId, anyObject.x, anyObject.y, anyObject.size, anyObject.padding, anyObject.style]); 759 | } 760 | } 761 | 762 | return [textDraws, guideGrids, guideLines]; 763 | } 764 | }; 765 | 766 | MultipleSelection.prototype.historyMultipleRemove = function(project, funcname, oldValue, newValue) 767 | { 768 | if(funcname == "applyOldValue") 769 | { 770 | let textDraws = newValue[0]; 771 | let guideGrids = newValue[1]; 772 | let guideLines = newValue[2]; 773 | 774 | for(let i = 0; i < textDraws.length; i++) 775 | { 776 | let textDraw = new TextDraw(project.main, textDraws[i][0], textDraws[i][1], textDraws[i][2], textDraws[i][3], textDraws[i][4]); 777 | 778 | textDraw.letterSizeX = textDraws[i][5]; 779 | textDraw.letterSizeY = textDraws[i][6]; 780 | textDraw.textSizeX = textDraws[i][7]; 781 | textDraw.textSizeY = textDraws[i][8]; 782 | textDraw.alignment = textDraws[i][9]; 783 | textDraw.color = textDraws[i][10]; 784 | textDraw.useBox = textDraws[i][11]; 785 | textDraw.boxColor = textDraws[i][12]; 786 | textDraw.setShadow = textDraws[i][13]; 787 | textDraw.setOutline = textDraws[i][14]; 788 | textDraw.backgroundColor = textDraws[i][15]; 789 | textDraw.font = textDraws[i][16]; 790 | textDraw.setProportional = textDraws[i][17]; 791 | textDraw.setVisibility(textDraws[i][18]); 792 | 793 | project.textDrawList.splice(textDraws[i][19], 0, textDraw); 794 | } 795 | 796 | for(let i = 0; i < guideGrids.length; i++) 797 | { 798 | let guideGrid = new GuideGrid(project.main, guideGrids[i][0], guideGrids[i][1], guideGrids[i][2], guideGrids[i][3], guideGrids[i][4], guideGrids[i][5], guideGrids[i][6], guideGrids[i][7], guideGrids[i][8], guideGrids[i][9]); 799 | guideGrid.setVisibility(guideGrids[i][10]); 800 | project.guideGrids.splice(guideGrids[i][11], 0, guideGrid); 801 | } 802 | 803 | for(let i = 0; i < guideLines.length; i++) 804 | { 805 | let guideLine = new GuideLine(project.main, guideLines[i][0], guideLines[i][1], guideLines[i][2], guideLines[i][3], guideLines[i][4], guideLines[i][5], guideLines[i][6]); 806 | guideLine.setVisibility(guideLines[i][7]); 807 | project.guideLines.splice(guideLines[i][8], 0, guideLine); 808 | } 809 | } 810 | else if(funcname == "applyNewValue") 811 | { 812 | let textDraws = oldValue[0]; 813 | let guideGrids = oldValue[1]; 814 | let guideLines = oldValue[2]; 815 | 816 | for(let i = 0; i < textDraws.length; i++) 817 | { 818 | let textDraw = project.findInternalId(textDraws[i][0]); 819 | 820 | if(textDraw) 821 | { 822 | project.removeTextDraw(textDraw); 823 | } 824 | } 825 | 826 | for(let i = 0; i < guideGrids.length; i++) 827 | { 828 | let guideGrid = project.findInternalId(guideGrids[i][0]); 829 | 830 | if(guideGrid) 831 | { 832 | project.removeGuideGrid(guideGrid); 833 | } 834 | } 835 | 836 | for(let i = 0; i < guideLines.length; i++) 837 | { 838 | let guideLine = project.findInternalId(guideLines[i][0]); 839 | 840 | if(guideLine) 841 | { 842 | project.removeGuideLine(guideLine); 843 | } 844 | } 845 | } 846 | else if(funcname == "updateOldValue") 847 | { 848 | let textDraws = []; 849 | let guideGrids = []; 850 | let guideLines = []; 851 | 852 | for(let i = 0; i < this.selections.length; i++) 853 | { 854 | let anyObject = this.selections[i]; 855 | 856 | if(anyObject instanceof TextDraw) 857 | { 858 | textDraws.push([anyObject.internalId, anyObject.name, anyObject.text, anyObject.x, anyObject.y, anyObject.letterSizeX, anyObject.letterSizeY, anyObject.textSizeX, anyObject.textSizeY, anyObject.alignment, anyObject.color, anyObject.useBox, anyObject.boxColor, anyObject.setShadow, anyObject.setOutline, anyObject.backgroundColor, anyObject.font, anyObject.setProportional, anyObject.visibility, anyObject.getMyIndex(project)]); 859 | } 860 | else if(anyObject instanceof GuideGrid) 861 | { 862 | guideGrids.push([anyObject.internalId, anyObject.name, anyObject.x, anyObject.y, anyObject.width, anyObject.height, anyObject.margin, anyObject.padding, anyObject.rows, anyObject.columns, anyObject.visibility, anyObject.getMyIndex(project)]); 863 | } 864 | else if(anyObject instanceof GuideLine) 865 | { 866 | guideLines.push([anyObject.internalId, anyObject.name, anyObject.x, anyObject.y, anyObject.size, anyObject.padding, anyObject.style, anyObject.visibility, anyObject.getMyIndex(project)]); 867 | } 868 | } 869 | 870 | return [textDraws, guideGrids, guideLines]; 871 | } 872 | else if(funcname == "updateNewValue") 873 | { 874 | return []; 875 | } 876 | }; 877 | 878 | MultipleSelection.prototype.historyRect = function(project, funcname, oldValue, newValue) 879 | { 880 | if(funcname == "applyOldValue" || funcname == "applyNewValue") 881 | { 882 | this.main.letterSizeOnResize = newValue[4]; 883 | 884 | this.rectLeft = oldValue[0]; 885 | this.rectTop = oldValue[1]; 886 | this.rectRight = oldValue[2]; 887 | this.rectBottom = oldValue[3]; 888 | 889 | for(let i = 0; i < this.selections.length; i++) 890 | { 891 | this.selections[i].percentLeft = this.selections[i].getRectLeft().getPercentOf(this.rectLeft, this.rectRight); 892 | this.selections[i].percentTop = this.selections[i].getRectTop().getPercentOf(this.rectTop, this.rectBottom); 893 | this.selections[i].percentRight = this.selections[i].getRectRight().getPercentOf(this.rectLeft, this.rectRight); 894 | this.selections[i].percentBottom = this.selections[i].getRectBottom().getPercentOf(this.rectTop, this.rectBottom); 895 | 896 | this.selections[i].oldLetterSizeX = this.selections[i].letterSizeX; 897 | this.selections[i].oldLetterSizeY = this.selections[i].letterSizeY; 898 | this.selections[i].oldWidth = this.selections[i].getRectRight() - this.selections[i].getRectLeft(); 899 | this.selections[i].oldHeight = this.selections[i].getRectBottom() - this.selections[i].getRectTop(); 900 | } 901 | 902 | this.setRectLeft(newValue[0]); 903 | this.setRectTop(newValue[1]); 904 | this.setRectRight(newValue[2]); 905 | this.setRectBottom(newValue[3]); 906 | } 907 | else if(funcname == "updateOldValue" || funcname == "updateNewValue") 908 | { 909 | return [this.rectLeft, this.rectTop, this.rectRight, this.rectBottom, this.main.letterSizeOnResize]; 910 | } 911 | }; 912 | -------------------------------------------------------------------------------- /assets/js/project.js: -------------------------------------------------------------------------------- 1 | 2 | function Project(main) 3 | { 4 | this.main = main; 5 | 6 | this.projectTabUI = new EntityUI(main.scrollableTabsUI, "div", {class: "projectTab", onclick: () => { main.changeProject(this); }, contextmenu: (e) => { main.contextMenuProject(this, e.clientX, e.clientY); e.preventDefault(); }}); 7 | this.thumbnailUI = new DrawableUI(this.projectTabUI, { width: "64", height: "64" }); 8 | 9 | this.textDrawList = []; 10 | this.guideGrids = []; 11 | this.guideLines = []; 12 | 13 | this.multipleSelection = new MultipleSelection(main); 14 | 15 | this.internalIdCounter = 0; 16 | 17 | this.history = [new HistoryData(HistoryType.Beginning, this, {internalId: -1})]; 18 | this.historyIdx = 0; 19 | this.unpushedHistoryData = null; 20 | this.historyBeginningSels = []; 21 | 22 | this.lastLoad = null; 23 | } 24 | 25 | Project.prototype.createTextDraw = function(text, x, y) 26 | { 27 | let textDraw = new TextDraw(this.main, ++this.internalIdCounter, this.getNewName("TextDraw", this.textDrawList), text, x, y); 28 | this.textDrawList.push(textDraw); 29 | return textDraw; 30 | }; 31 | 32 | Project.prototype.removeTextDraw = function(textDraw) 33 | { 34 | for(let i = 0; i < this.textDrawList.length; i++) 35 | { 36 | if(this.textDrawList[i] == textDraw) 37 | { 38 | this.textDrawList.splice(i, 1); 39 | break; 40 | } 41 | } 42 | 43 | textDraw.textDrawItemUI.remove(); 44 | }; 45 | 46 | Project.prototype.createGuideGrid = function(x, y, width, height, margin, padding, columns, rows) 47 | { 48 | let guideGrid = new GuideGrid(this.main, ++this.internalIdCounter, this.getNewName("GuideGrid", this.guideGrids), x, y, width, height, margin, padding, columns, rows); 49 | this.guideGrids.push(guideGrid); 50 | return guideGrid; 51 | }; 52 | 53 | Project.prototype.removeGuideGrid = function(guideGrid) 54 | { 55 | for(let i = 0; i < this.guideGrids.length; i++) 56 | { 57 | if(this.guideGrids[i] == guideGrid) 58 | { 59 | this.guideGrids.splice(i, 1); 60 | break; 61 | } 62 | } 63 | 64 | guideGrid.textDrawItemUI.remove(); 65 | }; 66 | 67 | Project.prototype.createGuideLine = function(x, y, size, margin, style) 68 | { 69 | let guideLine = new GuideLine(this.main, ++this.internalIdCounter, this.getNewName("GuideLine", this.guideLines), x, y, size, margin, style); 70 | this.guideLines.push(guideLine); 71 | return guideLine; 72 | }; 73 | 74 | Project.prototype.removeGuideLine = function(guideLine) 75 | { 76 | for(let i = 0; i < this.guideLines.length; i++) 77 | { 78 | if(this.guideLines[i] == guideLine) 79 | { 80 | this.guideLines.splice(i, 1); 81 | break; 82 | } 83 | } 84 | 85 | guideLine.textDrawItemUI.remove(); 86 | }; 87 | 88 | Project.prototype.getNewName = function(prefix, list) 89 | { 90 | for(let i = 1; ; i++) 91 | { 92 | let name = prefix + i; 93 | let used = false; 94 | 95 | for(let j = 0; j < list.length; j++) 96 | { 97 | if(list[j].name == name) 98 | { 99 | used = true; 100 | break; 101 | } 102 | } 103 | 104 | if(!used) 105 | return name; 106 | } 107 | }; 108 | 109 | Project.prototype.getCurrentTextDraw = function() 110 | { 111 | return this.multipleSelection.getCurrentTextDraw(); 112 | }; 113 | 114 | Project.prototype.getCurrentGuideGrid = function() 115 | { 116 | return this.multipleSelection.getCurrentGuideGrid(); 117 | }; 118 | 119 | Project.prototype.getCurrentGuideLine = function() 120 | { 121 | return this.multipleSelection.getCurrentGuideLine(); 122 | }; 123 | 124 | Project.prototype.getCurrentAnyObject = function() 125 | { 126 | return this.multipleSelection.getCurrentAnyObject(); 127 | }; 128 | 129 | Project.prototype.loadProject = function(savedProject, noLoadHistory) 130 | { 131 | if(!noLoadHistory) 132 | this.internalIdCounter = savedProject.internalIdCounter ?? 0; 133 | 134 | let savedTextDraws = savedProject.textDraws ?? []; 135 | 136 | for(let i = 0; i < savedTextDraws.length; i++) 137 | { 138 | if(noLoadHistory) 139 | savedTextDraws[i].internalId = undefined; 140 | 141 | let textDraw = new TextDraw(this.main, savedTextDraws[i].internalId ?? ++this.internalIdCounter, savedTextDraws[i].name, savedTextDraws[i].text, savedTextDraws[i].x, savedTextDraws[i].y); 142 | this.textDrawList.push(textDraw); 143 | textDraw.fromTextDraw(savedTextDraws[i]); 144 | 145 | if(savedTextDraws[i].hidden) 146 | { 147 | textDraw.visibility = false; 148 | textDraw.visibilityUI.element.style.backgroundPositionY = "-24px"; 149 | } 150 | 151 | if(savedTextDraws[i].selected) 152 | { 153 | this.multipleSelection.addSelection(textDraw); 154 | 155 | textDraw.textDrawItemUI.element.classList.add("currentTextDrawItem"); 156 | } 157 | 158 | if(this.lastLoad) 159 | this.lastLoad.push(textDraw); 160 | } 161 | 162 | let savedGuideGrids = savedProject.guideGrids ?? []; 163 | 164 | for(let i = 0; i < savedGuideGrids.length; i++) 165 | { 166 | if(noLoadHistory) 167 | savedGuideGrids[i].internalId = undefined; 168 | 169 | let guideGrid = new GuideGrid(this.main, savedGuideGrids[i].internalId ?? ++this.internalIdCounter, savedGuideGrids[i].name, savedGuideGrids[i].x, savedGuideGrids[i].y, savedGuideGrids[i].width, savedGuideGrids[i].height, savedGuideGrids[i].margin, savedGuideGrids[i].padding, savedGuideGrids[i].rows, savedGuideGrids[i].columns); 170 | this.guideGrids.push(guideGrid); 171 | 172 | if(savedGuideGrids[i].hidden) 173 | { 174 | guideGrid.visibility = false; 175 | guideGrid.visibilityUI.element.style.backgroundPositionY = "-24px"; 176 | } 177 | 178 | if(savedGuideGrids[i].selected) 179 | { 180 | this.multipleSelection.addSelection(guideGrid); 181 | 182 | guideGrid.textDrawItemUI.element.classList.add("currentTextDrawItem"); 183 | } 184 | 185 | if(this.lastLoad) 186 | this.lastLoad.push(guideGrid); 187 | } 188 | 189 | let savedGuideLines = savedProject.guideLines ?? []; 190 | 191 | for(let i = 0; i < savedGuideLines.length; i++) 192 | { 193 | if(noLoadHistory) 194 | savedGuideLines[i].internalId = undefined; 195 | 196 | let guideLine = new GuideLine(this.main, savedGuideLines[i].internalId ?? ++this.internalIdCounter, savedGuideLines[i].name, savedGuideLines[i].x, savedGuideLines[i].y, savedGuideLines[i].size, savedGuideLines[i].padding, savedGuideLines[i].style); 197 | this.guideLines.push(guideLine); 198 | 199 | if(savedGuideLines[i].hidden) 200 | { 201 | guideLine.visibility = false; 202 | guideLine.visibilityUI.element.style.backgroundPositionY = "-24px"; 203 | } 204 | 205 | if(savedGuideLines[i].selected) 206 | { 207 | this.multipleSelection.addSelection(guideLine); 208 | 209 | guideLine.textDrawItemUI.element.classList.add("currentTextDrawItem"); 210 | } 211 | 212 | if(this.lastLoad) 213 | this.lastLoad.push(guideLine); 214 | } 215 | 216 | let savedHistory = savedProject.history ?? []; 217 | 218 | if(!noLoadHistory && savedHistory.length > 1) 219 | { 220 | this.history = []; 221 | this.historyIdx = savedProject.historyIdx ?? 0; 222 | 223 | for(let i = 0; i < savedHistory.length; i++) 224 | { 225 | this.history.push(new HistoryData(HistoryTypeById[savedHistory[i].type], this, savedHistory[i])); 226 | } 227 | } 228 | else 229 | { 230 | this.history[0].selections = this.getSelectionsByInternalId(); 231 | } 232 | 233 | return this; 234 | }; 235 | 236 | Project.prototype.saveProject = function(noSaveHistory) 237 | { 238 | let savedTextDraws = []; 239 | 240 | for(let i = 0; i < this.textDrawList.length; i++) 241 | { 242 | let savedTextDraw = {}; 243 | 244 | this.textDrawList[i].copyTextDraw(savedTextDraw); 245 | 246 | if(noSaveHistory) 247 | savedTextDraw.internalId = undefined; 248 | 249 | if(!this.textDrawList[i].visibility) 250 | savedTextDraw.hidden = true; 251 | 252 | if(this.multipleSelection.isSelected(this.textDrawList[i])) 253 | savedTextDraw.selected = true; 254 | 255 | savedTextDraws.push(savedTextDraw); 256 | } 257 | 258 | let savedGuideGrids = []; 259 | 260 | for(let i = 0; i < this.guideGrids.length; i++) 261 | { 262 | let savedGuideGrid = {}; 263 | 264 | this.guideGrids[i].copyGuideGrid(savedGuideGrid); 265 | 266 | if(noSaveHistory) 267 | savedGuideGrid.internalId = undefined; 268 | 269 | if(!this.guideGrids[i].visibility) 270 | savedGuideGrid.hidden = true; 271 | 272 | if(this.multipleSelection.isSelected(this.guideGrids[i])) 273 | savedGuideGrid.selected = true; 274 | 275 | savedGuideGrids.push(savedGuideGrid); 276 | } 277 | 278 | let savedGuideLines = []; 279 | 280 | for(let i = 0; i < this.guideLines.length; i++) 281 | { 282 | let savedGuideLine = {}; 283 | 284 | this.guideLines[i].copyGuideLine(savedGuideLine); 285 | 286 | if(noSaveHistory) 287 | savedGuideLine.internalId = undefined; 288 | 289 | if(!this.guideLines[i].visibility) 290 | savedGuideLine.hidden = true; 291 | 292 | if(this.multipleSelection.isSelected(this.guideLines[i])) 293 | savedGuideLine.selected = true; 294 | 295 | savedGuideLines.push(savedGuideLine); 296 | } 297 | 298 | let savedHistory = []; 299 | let historyIdx = 0; 300 | 301 | if(!noSaveHistory && this.history.length > 1) 302 | { 303 | for(let i = 0; i < this.history.length; i++) 304 | { 305 | let savedHistoryData = {}; 306 | 307 | this.history[i].copyHistoryData(savedHistoryData); 308 | 309 | savedHistory.push(savedHistoryData); 310 | } 311 | 312 | historyIdx = this.historyIdx; 313 | } 314 | 315 | return {internalIdCounter: this.internalIdCounter, textDraws: savedTextDraws, guideGrids: savedGuideGrids, guideLines: savedGuideLines, history: savedHistory, historyIdx: historyIdx}; 316 | }; 317 | 318 | Project.prototype.findInternalId = function(internalId) 319 | { 320 | if(internalId == 0) 321 | return this.multipleSelection; 322 | 323 | for(let i = 0; i < this.textDrawList.length; i++) 324 | { 325 | if(this.textDrawList[i].internalId == internalId) 326 | return this.textDrawList[i]; 327 | } 328 | 329 | for(let i = 0; i < this.guideGrids.length; i++) 330 | { 331 | if(this.guideGrids[i].internalId == internalId) 332 | return this.guideGrids[i]; 333 | } 334 | 335 | for(let i = 0; i < this.guideLines.length; i++) 336 | { 337 | if(this.guideLines[i].internalId == internalId) 338 | return this.guideLines[i]; 339 | } 340 | 341 | return null; 342 | }; 343 | 344 | Project.prototype.getSelectionsByInternalId = function() 345 | { 346 | let selections = []; 347 | 348 | for(let i = 0; i < this.multipleSelection.selections.length; i++) 349 | { 350 | selections.push(this.multipleSelection.selections[i].internalId); 351 | } 352 | 353 | return selections; 354 | }; 355 | 356 | Project.prototype.setSelectionsByInternalId = function(selections) 357 | { 358 | this.multipleSelection = new MultipleSelection(main); 359 | 360 | for(let i = 0; i < selections.length; i++) 361 | { 362 | let anyObject = this.findInternalId(selections[i]); 363 | 364 | if(anyObject) 365 | { 366 | this.multipleSelection.addSelection(anyObject); 367 | } 368 | } 369 | }; 370 | 371 | Project.prototype.updateHistoryData = function(type, anyObject) 372 | { 373 | if(!anyObject) 374 | anyObject = this.getCurrentAnyObject(); 375 | 376 | if(anyObject) 377 | { 378 | if(this.unpushedHistoryData) 379 | { 380 | if(this.unpushedHistoryData.type == type && this.unpushedHistoryData.internalId == anyObject.internalId) 381 | { 382 | this.unpushedHistoryData.updateNewValue(this, anyObject); 383 | return; 384 | } 385 | 386 | this.pushHistoryData(); 387 | } 388 | 389 | this.unpushedHistoryData = new HistoryData(type, this, anyObject); 390 | 391 | if(this.historyIdx == 0) 392 | this.historyBeginningSels = this.getSelectionsByInternalId(); 393 | } 394 | }; 395 | 396 | Project.prototype.checkAndPushHistoryData = function(type, anyObject) 397 | { 398 | let ret = false; 399 | 400 | if(!anyObject) 401 | anyObject = this.getCurrentAnyObject(); 402 | 403 | if(anyObject) 404 | { 405 | if(this.unpushedHistoryData) 406 | { 407 | if(this.unpushedHistoryData.type == type && this.unpushedHistoryData.internalId == anyObject.internalId) 408 | { 409 | ret = this.pushHistoryData(); 410 | } 411 | } 412 | } 413 | 414 | return ret; 415 | }; 416 | 417 | Project.prototype.pushHistoryData = function() 418 | { 419 | let ret = false; 420 | 421 | if(this.unpushedHistoryData) 422 | { 423 | if(this.unpushedHistoryData.isValueChanged()) 424 | { 425 | if(this.historyIdx == 0) 426 | this.history[0].selections = this.historyBeginningSels; 427 | 428 | this.unpushedHistoryData.selections = this.getSelectionsByInternalId(); 429 | this.history.length = this.historyIdx + 1; 430 | this.history.push(this.unpushedHistoryData); 431 | this.historyIdx = this.history.length - 1; 432 | 433 | ret = true; 434 | } 435 | 436 | this.unpushedHistoryData = null; 437 | } 438 | 439 | return ret; 440 | }; 441 | 442 | Project.prototype.applyHistoryData = function(historyData) 443 | { 444 | let historyIdx = this.history.indexOf(historyData); 445 | 446 | if(historyIdx != -1) 447 | { 448 | if(this.historyIdx > historyIdx) 449 | { 450 | for(let i = this.historyIdx; i > historyIdx; i--) 451 | { 452 | if(this.history[i].type.setSelections) 453 | this.setSelectionsByInternalId(this.history[i].selections); 454 | 455 | this.history[i].applyOldValue(this); 456 | } 457 | } 458 | else 459 | { 460 | for(let i = this.historyIdx; i < historyIdx; i++) 461 | { 462 | if(this.history[i + 1].type.setSelections) 463 | this.setSelectionsByInternalId(this.history[i + 1].selections); 464 | 465 | this.history[i + 1].applyNewValue(this); 466 | } 467 | } 468 | 469 | this.setSelectionsByInternalId(this.history[historyIdx].selections); 470 | 471 | this.historyIdx = historyIdx; 472 | } 473 | }; 474 | 475 | Project.prototype.clearHistoryData = function() 476 | { 477 | this.history = [new HistoryData(HistoryType.Beginning, this, {internalId: -1})]; 478 | this.historyIdx = 0; 479 | this.unpushedHistoryData = null; 480 | this.historyBeginningSels = []; 481 | }; 482 | 483 | Project.prototype.historyTextDrawCreate = function(internalId, funcname, oldValue, newValue) 484 | { 485 | if(funcname == "applyNewValue") 486 | { 487 | let textDraw = new TextDraw(this.main, internalId, this.getNewName("TextDraw", this.textDrawList), newValue[0], newValue[1], newValue[2]); 488 | this.textDrawList.push(textDraw); 489 | } 490 | }; 491 | 492 | Project.prototype.historyTextDrawDuplicate = function(internalId, funcname, oldValue, newValue) 493 | { 494 | if(funcname == "applyNewValue") 495 | { 496 | let fromTextDraw = this.findInternalId(newValue[3]); 497 | 498 | if(fromTextDraw) 499 | { 500 | let copiedTextDraw = {}; 501 | fromTextDraw.copyTextDraw(copiedTextDraw); 502 | copiedTextDraw.width = fromTextDraw.getRectRight() - fromTextDraw.getRectLeft(); 503 | copiedTextDraw.height = fromTextDraw.getRectBottom() - fromTextDraw.getRectTop(); 504 | 505 | let textDraw = new TextDraw(this.main, internalId, this.getNewName("TextDraw", this.textDrawList), newValue[0], newValue[1], newValue[2]); 506 | textDraw.fromTextDraw(copiedTextDraw); 507 | this.textDrawList.push(textDraw); 508 | } 509 | } 510 | }; 511 | 512 | Project.prototype.historyTextDrawFromAnotherPoject = function(internalId, funcname, oldValue, newValue) 513 | { 514 | if(funcname == "applyNewValue") 515 | { 516 | let textDraw = new TextDraw(this.main, internalId, this.getNewName("TextDraw", this.textDrawList), newValue[0], newValue[1], newValue[2]); 517 | 518 | textDraw.letterSizeX = newValue[3]; 519 | textDraw.letterSizeY = newValue[4]; 520 | textDraw.textSizeX = newValue[5]; 521 | textDraw.textSizeY = newValue[6]; 522 | textDraw.alignment = newValue[7]; 523 | textDraw.color = newValue[8]; 524 | textDraw.useBox = newValue[9]; 525 | textDraw.boxColor = newValue[10]; 526 | textDraw.setShadow = newValue[11]; 527 | textDraw.setOutline = newValue[12]; 528 | textDraw.backgroundColor = newValue[13]; 529 | textDraw.font = newValue[14]; 530 | textDraw.setProportional = newValue[15]; 531 | 532 | this.textDrawList.push(textDraw); 533 | } 534 | }; 535 | 536 | Project.prototype.historyTextDrawRemove = function(internalId, funcname, oldValue, newValue) 537 | { 538 | if(funcname == "applyOldValue") 539 | { 540 | let textDraw = new TextDraw(this.main, internalId, newValue[0], newValue[1], newValue[2], newValue[3]); 541 | 542 | textDraw.letterSizeX = newValue[4]; 543 | textDraw.letterSizeY = newValue[5]; 544 | textDraw.textSizeX = newValue[6]; 545 | textDraw.textSizeY = newValue[7]; 546 | textDraw.alignment = newValue[8]; 547 | textDraw.color = newValue[9]; 548 | textDraw.useBox = newValue[10]; 549 | textDraw.boxColor = newValue[11]; 550 | textDraw.setShadow = newValue[12]; 551 | textDraw.setOutline = newValue[13]; 552 | textDraw.backgroundColor = newValue[14]; 553 | textDraw.font = newValue[15]; 554 | textDraw.setProportional = newValue[16]; 555 | textDraw.setVisibility(newValue[17]); 556 | 557 | this.textDrawList.splice(newValue[18], 0, textDraw); 558 | } 559 | }; 560 | 561 | Project.prototype.historyGuideGridCreate = function(internalId, funcname, oldValue, newValue) 562 | { 563 | if(funcname == "applyNewValue") 564 | { 565 | let guideGrid = new GuideGrid(this.main, internalId, this.getNewName("GuideGrid", this.guideGrids), newValue[0], newValue[1], newValue[2], newValue[3], newValue[4], newValue[5], newValue[6], newValue[7]); 566 | this.guideGrids.push(guideGrid); 567 | } 568 | }; 569 | 570 | Project.prototype.historyGuideGridRemove = function(internalId, funcname, oldValue, newValue) 571 | { 572 | if(funcname == "applyOldValue") 573 | { 574 | let guideGrid = new GuideGrid(this.main, internalId, newValue[0], newValue[1], newValue[2], newValue[3], newValue[4], newValue[5], newValue[6], newValue[7], newValue[8]); 575 | guideGrid.setVisibility(newValue[9]); 576 | this.guideGrids.splice(newValue[10], 0, guideGrid); 577 | } 578 | }; 579 | 580 | Project.prototype.historyGuideLineCreate = function(internalId, funcname, oldValue, newValue) 581 | { 582 | if(funcname == "applyNewValue") 583 | { 584 | let guideLine = new GuideLine(this.main, internalId, this.getNewName("GuideLine", this.guideLines), newValue[0], newValue[1], newValue[2], newValue[3], newValue[4]); 585 | this.guideLines.push(guideLine); 586 | } 587 | }; 588 | 589 | Project.prototype.historyGuideLineRemove = function(internalId, funcname, oldValue, newValue) 590 | { 591 | if(funcname == "applyOldValue") 592 | { 593 | let guideLine = new GuideLine(this.main, internalId, newValue[0], newValue[1], newValue[2], newValue[3], newValue[4], newValue[5]); 594 | guideLine.setVisibility(newValue[6]); 595 | this.guideLines.splice(newValue[7], 0, guideLine); 596 | } 597 | }; 598 | -------------------------------------------------------------------------------- /assets/js/textdraw.js: -------------------------------------------------------------------------------- 1 | 2 | function TextDraw(main, internalId, name, text, x, y) 3 | { 4 | this.main = main; 5 | this.internalId = internalId; 6 | 7 | this.textDrawItemUI = new EntityUI(null, "div", {class: "textDrawItem", onclick: (e) => { if(e.shiftKey) { main.adjacentAnyObject(this, e.ctrlKey); } else if(e.ctrlKey) { main.toggleAnyObject(this); } else { main.changeTextDraw(this); } }, contextmenu: (e) => { main.contextMenuTextDraw(this, e.clientX, e.clientY); e.preventDefault(); }}); 8 | this.thumbnailUI = new DrawableUI(this.textDrawItemUI, { width: "24", height: "24" }); 9 | this.nameUI = new EntityUI(this.textDrawItemUI, "span", {innerText: name}); 10 | this.visibilityUI = new EntityUI(this.textDrawItemUI, "div", {class: "visibility", onclick: (e) => { main.visibilityAnyObject(this); e.stopPropagation(); }}); 11 | 12 | this.linesWidth = []; 13 | this.linesCount = 0; 14 | 15 | this.stringWidth = 0; 16 | this.stringHeight = 0; 17 | 18 | this.name = name; 19 | this.text = text; 20 | this.x = x; 21 | this.y = y; 22 | this.letterSizeX = 1.0; 23 | this.letterSizeY = 3.5; 24 | this.textSizeX = x + 140.0; 25 | this.textSizeY = y + 32.0; 26 | this.alignment = 1; 27 | this.color = 0xFFFFFFFF; 28 | this.useBox = 1; 29 | this.boxColor = 0x000000AA; 30 | this.setShadow = 0; 31 | this.setOutline = 1; 32 | this.backgroundColor = 0x000000FF; 33 | this.font = 1; 34 | this.setProportional = 1; 35 | 36 | this.visibility = true; 37 | } 38 | 39 | TextDraw.prototype.copyTextDraw = function(textDraw) 40 | { 41 | textDraw.internalId = this.internalId; 42 | textDraw.name = this.name; 43 | textDraw.text = this.text; 44 | textDraw.x = this.x; 45 | textDraw.y = this.y; 46 | textDraw.letterSizeX = this.letterSizeX; 47 | textDraw.letterSizeY = this.letterSizeY; 48 | textDraw.textSizeX = this.textSizeX; 49 | textDraw.textSizeY = this.textSizeY; 50 | textDraw.alignment = this.alignment; 51 | textDraw.color = this.color; 52 | textDraw.useBox = this.useBox; 53 | textDraw.boxColor = this.boxColor; 54 | textDraw.setShadow = this.setShadow; 55 | textDraw.setOutline = this.setOutline; 56 | textDraw.backgroundColor = this.backgroundColor; 57 | textDraw.font = this.font; 58 | textDraw.setProportional = this.setProportional; 59 | }; 60 | 61 | TextDraw.prototype.fromTextDraw = function(textDraw) 62 | { 63 | this.letterSizeX = textDraw.letterSizeX; 64 | this.letterSizeY = textDraw.letterSizeY; 65 | this.textSizeX = textDraw.textSizeX; 66 | this.textSizeY = textDraw.textSizeY; 67 | this.alignment = textDraw.alignment; 68 | this.color = textDraw.color; 69 | this.useBox = textDraw.useBox; 70 | this.boxColor = textDraw.boxColor; 71 | this.setShadow = textDraw.setShadow; 72 | this.setOutline = textDraw.setOutline; 73 | this.backgroundColor = textDraw.backgroundColor; 74 | this.font = textDraw.font; 75 | this.setProportional = textDraw.setProportional; 76 | 77 | if(textDraw.width && textDraw.height) 78 | { 79 | this.setRectRight(this.getRectLeft() + textDraw.width); 80 | this.setRectBottom(this.getRectTop() + textDraw.height); 81 | } 82 | }; 83 | 84 | TextDraw.prototype.offsetRect = function(offsetX, offsetY) 85 | { 86 | if(this.font == 4 || this.font == 5) 87 | { 88 | this.x += offsetX; 89 | this.y += offsetY; 90 | return; 91 | } 92 | 93 | switch(this.alignment) 94 | { 95 | case 1: 96 | this.x += offsetX; 97 | this.y += offsetY; 98 | this.textSizeX += offsetX; 99 | this.textSizeY += offsetY; 100 | break; 101 | 102 | case 2: 103 | this.x += offsetX; 104 | this.y += offsetY; 105 | this.textSizeX += offsetY; 106 | break; 107 | 108 | case 3: 109 | this.x += offsetX; 110 | this.y += offsetY; 111 | this.textSizeX -= offsetX; 112 | this.textSizeY += offsetY; 113 | break; 114 | } 115 | }; 116 | 117 | TextDraw.prototype.setRectLeft = function(rectLeft) 118 | { 119 | if(this.font == 4 || this.font == 5) 120 | { 121 | this.textSizeX = this.getRectRight() - rectLeft; 122 | this.x = rectLeft; 123 | return; 124 | } 125 | 126 | switch(this.alignment) 127 | { 128 | case 1: 129 | this.x = rectLeft; 130 | break; 131 | 132 | case 2: 133 | this.textSizeY = this.getRectRight() - rectLeft; 134 | this.x = rectLeft + this.textSizeY / 2; 135 | break; 136 | 137 | case 3: 138 | this.textSizeX = 640 - rectLeft; 139 | break; 140 | } 141 | }; 142 | 143 | TextDraw.prototype.setRectTop = function(rectTop) 144 | { 145 | if(this.font == 4 || this.font == 5) 146 | { 147 | this.textSizeY = this.getRectBottom() - rectTop; 148 | this.y = rectTop; 149 | return; 150 | } 151 | 152 | this.y = rectTop; 153 | }; 154 | 155 | TextDraw.prototype.setRectRight = function(rectRight) 156 | { 157 | if(this.font == 4 || this.font == 5) 158 | { 159 | this.textSizeX = rectRight - this.x; 160 | return; 161 | } 162 | 163 | switch(this.alignment) 164 | { 165 | case 1: 166 | this.textSizeX = rectRight; 167 | break; 168 | 169 | case 2: 170 | this.textSizeY = rectRight - this.getRectLeft(); 171 | this.x = rectRight - this.textSizeY / 2; 172 | break; 173 | 174 | case 3: 175 | this.x = rectRight; 176 | break; 177 | } 178 | }; 179 | 180 | TextDraw.prototype.setRectBottom = function(rectBottom) 181 | { 182 | if(this.font == 4 || this.font == 5) 183 | { 184 | this.textSizeY = rectBottom - this.y; 185 | return; 186 | } 187 | 188 | switch(this.alignment) 189 | { 190 | case 1: 191 | this.textSizeY = rectBottom; 192 | break; 193 | 194 | case 2: 195 | this.textSizeX = rectBottom; 196 | break; 197 | 198 | case 3: 199 | this.textSizeY = rectBottom; 200 | break; 201 | } 202 | }; 203 | 204 | TextDraw.prototype.getRectLeft = function() 205 | { 206 | if(this.font == 4 || this.font == 5) 207 | return this.x; 208 | 209 | let rectLeft = 0; 210 | 211 | switch(this.alignment) 212 | { 213 | case 1: 214 | rectLeft = this.x; 215 | break; 216 | 217 | case 2: 218 | rectLeft = this.x - this.textSizeY / 2; 219 | break; 220 | 221 | case 3: 222 | rectLeft = 640 - this.textSizeX; 223 | break; 224 | } 225 | 226 | return rectLeft; 227 | }; 228 | 229 | TextDraw.prototype.getRectTop = function() 230 | { 231 | return this.y; 232 | }; 233 | 234 | TextDraw.prototype.getRectRight = function() 235 | { 236 | if(this.font == 4 || this.font == 5) 237 | return this.x + this.textSizeX; 238 | 239 | let rectRight = 0; 240 | 241 | switch(this.alignment) 242 | { 243 | case 1: 244 | rectRight = this.textSizeX; 245 | break; 246 | 247 | case 2: 248 | rectRight = this.x + this.textSizeY / 2; 249 | break; 250 | 251 | case 3: 252 | rectRight = this.x; 253 | break; 254 | } 255 | 256 | return rectRight; 257 | }; 258 | 259 | TextDraw.prototype.getRectBottom = function() 260 | { 261 | if(this.font == 4 || this.font == 5) 262 | return this.y + this.textSizeY; 263 | 264 | let rectBottom = 0; 265 | 266 | switch(this.alignment) 267 | { 268 | case 1: 269 | rectBottom = this.textSizeY; 270 | break; 271 | 272 | case 2: 273 | rectBottom = this.textSizeX; 274 | break; 275 | 276 | case 3: 277 | rectBottom = this.textSizeY; 278 | break; 279 | } 280 | 281 | return rectBottom; 282 | }; 283 | 284 | TextDraw.prototype.getPaddingLeft = function() 285 | { 286 | if(this.font == 4 || this.font == 5) 287 | return 0; 288 | 289 | let paddingLeft = 0; 290 | 291 | switch(this.alignment) 292 | { 293 | case 1: 294 | break; 295 | 296 | case 2: 297 | paddingLeft += this.textSizeY / 2; 298 | paddingLeft -= this.stringWidth / 2 * this.letterSizeX; 299 | paddingLeft -= this.letterSizeX / 2; 300 | break; 301 | 302 | case 3: 303 | paddingLeft += this.getRectRight() - this.getRectLeft(); 304 | paddingLeft -= this.stringWidth * this.letterSizeX; 305 | break; 306 | } 307 | 308 | return paddingLeft; 309 | }; 310 | 311 | TextDraw.prototype.getStringRectLeft = function() 312 | { 313 | return this.getRectLeft() + this.getPaddingLeft(); 314 | }; 315 | 316 | TextDraw.prototype.getStringRectTop = function() 317 | { 318 | return this.getRectTop(); 319 | }; 320 | 321 | TextDraw.prototype.getStringRectRight = function() 322 | { 323 | if(this.font == 4 || this.font == 5) 324 | return this.getRectRight(); 325 | 326 | return this.getStringRectLeft() + this.stringWidth * this.letterSizeX; 327 | }; 328 | 329 | TextDraw.prototype.getStringRectBottom = function() 330 | { 331 | if(this.font == 4 || this.font == 5) 332 | return this.getRectBottom(); 333 | 334 | return this.getStringRectTop() + 9.0 * this.linesCount * this.letterSizeY; 335 | }; 336 | 337 | TextDraw.prototype.getMargin = function() 338 | { 339 | if(this.font == 4 || this.font == 5 || this.useBox == 0) 340 | return 0.0; 341 | 342 | return 4.0; 343 | }; 344 | 345 | TextDraw.prototype.getBoxColor = function() 346 | { 347 | if(this.font == 4) 348 | return this.color; 349 | 350 | if(this.font == 5) 351 | return this.color & this.backgroundColor; 352 | 353 | return this.boxColor; 354 | }; 355 | 356 | TextDraw.prototype.changeAlignment = function(alignment) 357 | { 358 | let rectLeft = this.getRectLeft(); 359 | let rectTop = this.getRectTop(); 360 | let rectRight = this.getRectRight(); 361 | let rectBottom = this.getRectBottom(); 362 | 363 | switch(alignment) 364 | { 365 | case 1: 366 | case 2: 367 | case 3: 368 | this.alignment = alignment; 369 | break; 370 | } 371 | 372 | this.setRectLeft(rectLeft); 373 | this.setRectTop(rectTop); 374 | this.setRectRight(rectRight); 375 | this.setRectBottom(rectBottom); 376 | }; 377 | 378 | TextDraw.prototype.changeFont = function(font) 379 | { 380 | let rectLeft = this.getRectLeft(); 381 | let rectTop = this.getRectTop(); 382 | let rectRight = this.getRectRight(); 383 | let rectBottom = this.getRectBottom(); 384 | 385 | switch(font) 386 | { 387 | case 0: 388 | case 1: 389 | case 2: 390 | case 3: 391 | case 4: 392 | case 5: 393 | this.font = font; 394 | break; 395 | } 396 | 397 | this.setRectLeft(rectLeft); 398 | this.setRectTop(rectTop); 399 | this.setRectRight(rectRight); 400 | this.setRectBottom(rectBottom); 401 | }; 402 | 403 | TextDraw.prototype.setVisibility = function(visibility) 404 | { 405 | this.visibility = visibility; 406 | this.visibilityUI.element.style.backgroundPositionY = visibility ? "0px" : "-24px"; 407 | }; 408 | 409 | TextDraw.prototype.getMyIndex = function(project) 410 | { 411 | return project.textDrawList.indexOf(this); 412 | }; 413 | 414 | TextDraw.prototype.historyTextDrawCreate = function(project, funcname, oldValue, newValue) 415 | { 416 | if(funcname == "applyOldValue") 417 | { 418 | project.removeTextDraw(this); 419 | } 420 | else if(funcname == "updateOldValue") 421 | { 422 | return []; 423 | } 424 | else if(funcname == "updateNewValue") 425 | { 426 | return [this.text, this.x, this.y]; 427 | } 428 | }; 429 | 430 | TextDraw.prototype.historyTextDrawDuplicate = function(project, funcname, oldValue, newValue) 431 | { 432 | if(funcname == "applyOldValue") 433 | { 434 | project.removeTextDraw(this); 435 | } 436 | else if(funcname == "updateOldValue") 437 | { 438 | return []; 439 | } 440 | else if(funcname == "updateNewValue") 441 | { 442 | return [this.text, this.x, this.y, this.duplicateFromInternalId]; 443 | } 444 | }; 445 | 446 | TextDraw.prototype.historyTextDrawFromAnotherPoject = function(project, funcname, oldValue, newValue) 447 | { 448 | if(funcname == "applyOldValue") 449 | { 450 | project.removeTextDraw(this); 451 | } 452 | else if(funcname == "updateOldValue") 453 | { 454 | return []; 455 | } 456 | else if(funcname == "updateNewValue") 457 | { 458 | return [this.text, this.x, this.y, this.letterSizeX, this.letterSizeY, this.textSizeX, this.textSizeY, this.alignment, this.color, this.useBox, this.boxColor, this.setShadow, this.setOutline, this.backgroundColor, this.font, this.setProportional]; 459 | } 460 | }; 461 | 462 | TextDraw.prototype.historyTextDrawRemove = function(project, funcname, oldValue, newValue) 463 | { 464 | if(funcname == "applyNewValue") 465 | { 466 | project.removeTextDraw(this); 467 | } 468 | else if(funcname == "updateOldValue") 469 | { 470 | return [this.name, this.text, this.x, this.y, this.letterSizeX, this.letterSizeY, this.textSizeX, this.textSizeY, this.alignment, this.color, this.useBox, this.boxColor, this.setShadow, this.setOutline, this.backgroundColor, this.font, this.setProportional, this.visibility, this.getMyIndex(project)]; 471 | } 472 | else if(funcname == "updateNewValue") 473 | { 474 | return []; 475 | } 476 | }; 477 | 478 | TextDraw.prototype.historyAlignment = function(project, funcname, oldValue, newValue) 479 | { 480 | if(funcname == "applyOldValue" || funcname == "applyNewValue") 481 | { 482 | this.changeAlignment(newValue); 483 | } 484 | else if(funcname == "updateOldValue" || funcname == "updateNewValue") 485 | { 486 | return this.alignment; 487 | } 488 | }; 489 | 490 | TextDraw.prototype.historyFont = function(project, funcname, oldValue, newValue) 491 | { 492 | if(funcname == "applyOldValue" || funcname == "applyNewValue") 493 | { 494 | this.changeFont(newValue); 495 | } 496 | else if(funcname == "updateOldValue" || funcname == "updateNewValue") 497 | { 498 | return this.font; 499 | } 500 | }; 501 | 502 | TextDraw.prototype.historyVisibility = function(project, funcname, oldValue, newValue) 503 | { 504 | if(funcname == "applyOldValue" || funcname == "applyNewValue") 505 | { 506 | this.setVisibility(newValue); 507 | } 508 | else if(funcname == "updateOldValue" || funcname == "updateNewValue") 509 | { 510 | return this.visibility; 511 | } 512 | }; 513 | -------------------------------------------------------------------------------- /assets/js/txd/texturedictionary.js: -------------------------------------------------------------------------------- 1 | 2 | function TextureDictionary(name, bytes) 3 | { 4 | this.name = name; 5 | this.textures = [] 6 | 7 | this.processTxd(bytes); 8 | } 9 | 10 | TextureDictionary.prototype.processTxd = function(bytes) 11 | { 12 | let id = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); 13 | let size = bytes[4] | (bytes[5] << 8) | (bytes[6] << 16) | (bytes[7] << 24); 14 | 15 | switch(id) 16 | { 17 | case 0x16: 18 | this.processTxdFile(bytes, 12, 12 + size); 19 | break; 20 | } 21 | }; 22 | 23 | TextureDictionary.prototype.processTxdFile = function(bytes, pos, end) 24 | { 25 | while(pos < end) 26 | { 27 | let id = bytes[pos + 0] | (bytes[pos + 1] << 8) | (bytes[pos + 2] << 16) | (bytes[pos + 3] << 24); 28 | let size = bytes[pos + 4] | (bytes[pos + 5] << 8) | (bytes[pos + 6] << 16) | (bytes[pos + 7] << 24); 29 | 30 | switch(id) 31 | { 32 | case 0x01: 33 | this.processTxdInfo(bytes, pos + 12, pos + 12 + size); 34 | break; 35 | 36 | case 0x15: 37 | this.processTxdTexture(bytes, pos + 12, pos + 12 + size); 38 | break; 39 | } 40 | 41 | pos += size + 12; 42 | } 43 | }; 44 | 45 | TextureDictionary.prototype.processTxdInfo = function(bytes, pos, end) 46 | { 47 | 48 | }; 49 | 50 | TextureDictionary.prototype.processTxdTexture = function(bytes, pos, end) 51 | { 52 | while(pos < end) 53 | { 54 | let id = bytes[pos + 0] | (bytes[pos + 1] << 8) | (bytes[pos + 2] << 16) | (bytes[pos + 3] << 24); 55 | let size = bytes[pos + 4] | (bytes[pos + 5] << 8) | (bytes[pos + 6] << 16) | (bytes[pos + 7] << 24); 56 | 57 | switch(id) 58 | { 59 | case 0x01: 60 | this.processTxdTextureData(bytes, pos + 12, pos + 12 + size); 61 | break; 62 | 63 | case 0x03: 64 | this.processTxdExtraInfo(bytes, pos + 12, pos + 12 + size); 65 | break; 66 | } 67 | 68 | pos += size + 12; 69 | } 70 | }; 71 | 72 | TextureDictionary.prototype.processTxdTextureData = function(bytes, pos, end) 73 | { 74 | let name = ""; 75 | 76 | for(let j = 0; j < 32; j++) 77 | { 78 | if(bytes[pos + 8 + j] == 0) 79 | break; 80 | 81 | name += String.fromCharCode(bytes[pos + 8 + j]); 82 | } 83 | 84 | name = name.toLowerCase(); 85 | 86 | let rasterFormat = bytes[pos + 72] | (bytes[pos + 73] << 8) | (bytes[pos + 74] << 16) | (bytes[pos + 75] << 24); 87 | let d3dFormat = bytes[pos + 76] | (bytes[pos + 77] << 8) | (bytes[pos + 78] << 16) | (bytes[pos + 79] << 24); 88 | let width = bytes[pos + 80] | (bytes[pos + 81] << 8); 89 | let height = bytes[pos + 82] | (bytes[pos + 83] << 8); 90 | let depth = bytes[pos + 84]; 91 | 92 | if(depth == 8) 93 | pos += 1024; 94 | 95 | let size = bytes[pos + 88] | (bytes[pos + 89] << 8) | (bytes[pos + 90] << 16) | (bytes[pos + 91] << 24); 96 | 97 | pos += 92; 98 | 99 | let imageUI = new DrawableUI(null, {width: width, height: height}); 100 | let imageData = imageUI.context.getImageData(0, 0, width, height); 101 | 102 | let idx = 0; 103 | 104 | switch(d3dFormat) 105 | { 106 | case 0x31545844: // DXT1 107 | decompressDXT(width, height, bytes.slice(pos, pos + size), imageData.data, DXT1BlockSize, decompressBlockDXT1) 108 | break; 109 | 110 | case 0x33545844: // DXT3 111 | decompressDXT(width, height, bytes.slice(pos, pos + size), imageData.data, DXT3BlockSize, decompressBlockDXT3) 112 | break; 113 | 114 | default: 115 | switch(rasterFormat & 0xFFF) 116 | { 117 | case 0x0500: // D3DFMT_A8R8G8B8 118 | while(idx < size) 119 | { 120 | imageData.data[idx ] = bytes[pos + idx + 2]; 121 | imageData.data[idx + 1] = bytes[pos + idx + 1]; 122 | imageData.data[idx + 2] = bytes[pos + idx]; 123 | imageData.data[idx + 3] = bytes[pos + idx + 3]; 124 | idx += 4; 125 | } 126 | 127 | break; 128 | 129 | case 0x0600: // D3DFMT_X8R8G8B8 130 | while(idx < size) 131 | { 132 | imageData.data[idx ] = bytes[pos + idx + 2]; 133 | imageData.data[idx + 1] = bytes[pos + idx + 1]; 134 | imageData.data[idx + 2] = bytes[pos + idx]; 135 | imageData.data[idx + 3] = 0xFF; 136 | idx += 4; 137 | } 138 | 139 | break; 140 | 141 | default: 142 | console.log("[Unsupported format] d3dFormat: " + d3dFormat.toString(16) + ", rasterFormat: " + rasterFormat.toString(16)); 143 | break; 144 | } 145 | 146 | break; 147 | } 148 | 149 | imageUI.context.putImageData(imageData, 0, 0); 150 | 151 | this.textures.push({name: name, imageUI: imageUI}); 152 | }; 153 | 154 | TextureDictionary.prototype.processTxdExtraInfo = function(bytes, pos, end) 155 | { 156 | 157 | }; 158 | 159 | TextureDictionary.instances = []; 160 | TextureDictionary.updateEventListeners = []; 161 | 162 | TextureDictionary.newInstance = function(name, bytes) 163 | { 164 | let instance = new TextureDictionary(name, bytes); 165 | TextureDictionary.instances.push(instance); 166 | TextureDictionary.updateEvent(); 167 | return instance; 168 | }; 169 | 170 | TextureDictionary.updateEvent = function() 171 | { 172 | for(let i = 0; i < TextureDictionary.updateEventListeners.length; i++) 173 | TextureDictionary.updateEventListeners[i](); 174 | }; 175 | -------------------------------------------------------------------------------- /assets/js/txd/texturemanager.js: -------------------------------------------------------------------------------- 1 | 2 | function TextureManager() 3 | { 4 | this.lastTxdName = ""; 5 | this.lastTexture = {name: "", imageUI: null}; 6 | this.lastColor = 0; 7 | 8 | this.colorUI = null; 9 | } 10 | 11 | TextureManager.prototype.loadTexture = function(name, color) 12 | { 13 | let txdAndTexName = name.toLowerCase().split(":", 2); 14 | 15 | if(txdAndTexName.length == 2) 16 | { 17 | let txdName = txdAndTexName[0]; 18 | let texName = txdAndTexName[1]; 19 | 20 | if(this.lastTxdName == txdName && this.lastTexture.name == texName) 21 | { 22 | if(color != 0xFFFFFFFF) 23 | { 24 | if(this.lastColor != color) 25 | { 26 | this.lastColor = color; 27 | this.setColor(color); 28 | } 29 | 30 | return this.colorUI; 31 | } 32 | 33 | return this.lastTexture.imageUI; 34 | } 35 | 36 | for(let i = 0; i < TextureDictionary.instances.length; i++) 37 | { 38 | let textureDictionary = TextureDictionary.instances[i]; 39 | 40 | if(textureDictionary.name == txdName) 41 | { 42 | for(let j = 0; j < textureDictionary.textures.length; j++) 43 | { 44 | let texture = textureDictionary.textures[j]; 45 | 46 | if(texture.name == texName) 47 | { 48 | this.lastTxdName = txdName; 49 | this.lastTexture = texture; 50 | this.lastColor = color; 51 | 52 | if(color != 0xFFFFFFFF) 53 | { 54 | this.setColor(color); 55 | return this.colorUI; 56 | } 57 | 58 | return texture.imageUI; 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | return null; 66 | }; 67 | 68 | TextureManager.prototype.setColor = function(color) 69 | { 70 | let width = this.lastTexture.imageUI.element.width; 71 | let height = this.lastTexture.imageUI.element.height; 72 | 73 | if(!this.colorUI) 74 | { 75 | this.colorUI = new DrawableUI(null, {width: width, height: height}); 76 | } 77 | else if(this.colorUI.element.width != width || this.colorUI.element.height != height) 78 | { 79 | this.colorUI.element.width = width; 80 | this.colorUI.element.height = height; 81 | } 82 | 83 | this.colorUI.context.clearRect(0, 0, width, height); 84 | this.colorUI.context.globalCompositeOperation = "copy"; 85 | this.colorUI.context.drawImage(this.lastTexture.imageUI.element, 0, 0, width, height, 0, 0, width, height); 86 | this.colorUI.context.globalCompositeOperation = "multiply"; 87 | this.colorUI.context.fillStyle = color.toRGB(); 88 | this.colorUI.context.fillRect(0, 0, width, height); 89 | this.colorUI.context.globalCompositeOperation = "destination-atop"; 90 | this.colorUI.context.globalAlpha = color.getAlpha(); 91 | this.colorUI.context.drawImage(this.lastTexture.imageUI.element, 0, 0, width, height, 0, 0, width, height); 92 | this.colorUI.context.globalAlpha = 1; 93 | }; 94 | 95 | TextureManager.instance = new TextureManager(); 96 | -------------------------------------------------------------------------------- /assets/js/ui/buttonui.js: -------------------------------------------------------------------------------- 1 | 2 | function ButtonUI(parent, setting) 3 | { 4 | EntityUI.call(this, parent, "button", setting); 5 | } 6 | 7 | ButtonUI.prototype = Object.create(EntityUI.prototype); 8 | -------------------------------------------------------------------------------- /assets/js/ui/contextmenuui.js: -------------------------------------------------------------------------------- 1 | 2 | function ContextMenuUI(parent, x, y) 3 | { 4 | if(parent instanceof EntityUI && parent.element.classList.contains("contextItem")) 5 | { 6 | parent.rightPointingUI = new EntityUI(parent, "div", {class: "rightPointing"}); 7 | } 8 | 9 | EntityUI.call(this, parent, "div", {class: "contextMenu", contextmenu: (e) => { e.preventDefault(); }}); 10 | 11 | this.element.style.left = x + "px"; 12 | this.element.style.top = y + "px"; 13 | } 14 | 15 | ContextMenuUI.prototype = Object.create(EntityUI.prototype); 16 | 17 | ContextMenuUI.prototype.appendItem = function(text, click, icon) 18 | { 19 | let setting; 20 | 21 | if(click === false) 22 | { 23 | setting = {innerText: text, class: "contextItem"}; 24 | } 25 | else if(click) 26 | { 27 | setting = {innerText: text, class: "contextItem", click: () => { click(); this.remove(); }}; 28 | } 29 | else 30 | { 31 | setting = {innerText: text, class: ["contextItem", "contextItemDisabled"]}; 32 | } 33 | 34 | if(icon) 35 | { 36 | setting.style = {backgroundImage: "url(./assets/images/icon-" + icon + ".png)"}; 37 | } 38 | 39 | return new EntityUI(this, "div", setting); 40 | }; 41 | 42 | ContextMenuUI.prototype.getSubMenuList = function() 43 | { 44 | let subMenuList = []; 45 | 46 | for(let i = 0; i < this.element.childNodes.length; i++) 47 | { 48 | let element = this.element.childNodes[i].querySelector(":scope > .contextMenu"); 49 | 50 | if(element && element.entityUI) 51 | subMenuList.push(element.entityUI); 52 | } 53 | 54 | return subMenuList; 55 | }; 56 | 57 | ContextMenuUI.prototype.updateSubMenuPosition = function() 58 | { 59 | let subMenuList = this.getSubMenuList(); 60 | let subMenuPosX = 0; 61 | let subMenuPosY = -(this.element.clientTop + this.element.firstChild.offsetTop); 62 | 63 | for(let i = 0; i < subMenuList.length; i++) 64 | { 65 | if(subMenuList[i].element.parentNode.clientWidth > subMenuPosX) 66 | subMenuPosX = subMenuList[i].element.parentNode.clientWidth; 67 | } 68 | 69 | for(let i = 0; i < subMenuList.length; i++) 70 | { 71 | subMenuList[i].element.style.left = subMenuPosX + "px"; 72 | subMenuList[i].element.style.top = subMenuPosY + "px"; 73 | subMenuList[i].updateSubMenuPosition(); 74 | } 75 | }; 76 | 77 | ContextMenuUI.prototype.remove = function() 78 | { 79 | if(this.element.parentNode && this.element.parentNode.entityUI && this.element.parentNode.entityUI instanceof EntityUI) 80 | { 81 | let contextItemUI = this.element.parentNode.entityUI; 82 | 83 | if(contextItemUI.element.parentNode && contextItemUI.element.parentNode.entityUI && contextItemUI.element.parentNode.entityUI instanceof ContextMenuUI) 84 | { 85 | contextItemUI.element.parentNode.entityUI.remove(); 86 | return; 87 | } 88 | } 89 | 90 | EntityUI.prototype.remove.call(this); 91 | }; 92 | 93 | ContextMenuUI.prototype.isInBoundingClientRect = function(x, y) 94 | { 95 | if(EntityUI.prototype.isInBoundingClientRect.call(this, x, y)) 96 | return true; 97 | 98 | let subMenuList = this.getSubMenuList(); 99 | 100 | for(let i = 0; i < subMenuList.length; i++) 101 | { 102 | if(EntityUI.prototype.isInBoundingClientRect.call(subMenuList[i], x, y)) 103 | return true; 104 | } 105 | 106 | return false; 107 | }; 108 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function DialogUI(parent, title) 3 | { 4 | EntityUI.call(this, parent, "div", {class: "dialog", mousedown: () => { this.focus(); }}); 5 | 6 | this.moving = false; 7 | this.movingX = 0; 8 | this.movingY = 0; 9 | 10 | this.boundings = null; 11 | 12 | this.position = {}; 13 | 14 | this.titleBarUI = new EntityUI(this, "div", {innerText: title, class: "dialogTitleBar", mousedown: (e) => { this.startMoving(e); }}); 15 | this.contentUI = new EntityUI(this, "div", {class: "dialogContent"}); 16 | this.buttonsUI = new EntityUI(this, "div", {class: "dialogButtons"}); 17 | 18 | this.focus(); 19 | } 20 | 21 | DialogUI.prototype = Object.create(EntityUI.prototype); 22 | 23 | DialogUI.prototype.startMoving = function(e) 24 | { 25 | main.overrideCursor(true); 26 | 27 | document.body.style.cursor = "move"; 28 | document.body.style.userSelect = "none"; 29 | 30 | this.moving = true; 31 | this.movingX = e.clientX - this.element.getBoundingClientRect().left; 32 | this.movingY = e.clientY - this.element.getBoundingClientRect().top; 33 | 34 | this.boundings = []; 35 | 36 | let elements = document.querySelectorAll(".dialog"); 37 | 38 | for(let i = 0; i < elements.length; i++) 39 | { 40 | if(this.element == elements[i]) 41 | continue; 42 | 43 | this.boundings.push(elements[i].getBoundingClientRect()); 44 | } 45 | }; 46 | 47 | DialogUI.prototype.stopMoving = function(e) 48 | { 49 | main.overrideCursor(false); 50 | 51 | document.body.style.cursor = ""; 52 | document.body.style.userSelect = ""; 53 | 54 | this.moving = false; 55 | this.movingX = 0; 56 | this.movingY = 0; 57 | 58 | this.boundings = null; 59 | }; 60 | 61 | DialogUI.prototype.move = function(x, y) 62 | { 63 | if(x < 0 || this.element.offsetWidth >= window.innerWidth) 64 | { 65 | x = 0; 66 | } 67 | else if(x >= (window.innerWidth - this.element.offsetWidth)) 68 | { 69 | x = window.innerWidth - this.element.offsetWidth - 1; 70 | } 71 | 72 | if(y < 0 || this.element.offsetHeight >= window.innerHeight) 73 | { 74 | y = 0; 75 | } 76 | else if(y >= (window.innerHeight - this.element.offsetHeight)) 77 | { 78 | y = window.innerHeight - this.element.offsetHeight - 1; 79 | } 80 | 81 | if(this.boundings) 82 | { 83 | let sizeX = this.element.offsetWidth; 84 | let sizeY = this.element.offsetHeight; 85 | 86 | let centerX = x + sizeX / 2; 87 | let centerY = y + sizeY / 2; 88 | 89 | let left = x; 90 | let top = y; 91 | let right = x + sizeX; 92 | let bottom = y + sizeY; 93 | 94 | for(let i = 0; i < this.boundings.length; i++) 95 | { 96 | let sizeX2 = this.boundings[i].right - this.boundings[i].left; 97 | let sizeY2 = this.boundings[i].bottom - this.boundings[i].top; 98 | 99 | let centerX2 = this.boundings[i].left + sizeX2 / 2; 100 | let centerY2 = this.boundings[i].top + sizeY2 / 2; 101 | 102 | if((this.boundings[i].left < centerX && centerX < this.boundings[i].right) || (left < centerX2 && centerX2 < right)) 103 | { 104 | if(Math.abs(this.boundings[i].top - bottom) <= 4) 105 | { 106 | y = this.boundings[i].top - sizeY + 1; 107 | } 108 | else if(Math.abs(this.boundings[i].bottom - top) <= 4) 109 | { 110 | y = this.boundings[i].bottom - 1; 111 | } 112 | else 113 | { 114 | continue; 115 | } 116 | 117 | if(Math.abs(this.boundings[i].left - left) <= 4) 118 | { 119 | x = this.boundings[i].left; 120 | } 121 | else if(Math.abs(this.boundings[i].right - right) <= 4) 122 | { 123 | x = this.boundings[i].right - sizeX; 124 | } 125 | 126 | break; 127 | } 128 | else if((this.boundings[i].top < centerY && centerY < this.boundings[i].bottom) || (top < centerY2 && centerY2 < bottom)) 129 | { 130 | if(Math.abs(this.boundings[i].left - right) <= 4) 131 | { 132 | x = this.boundings[i].left - sizeX + 1; 133 | } 134 | else if(Math.abs(this.boundings[i].right - left) <= 4) 135 | { 136 | x = this.boundings[i].right - 1; 137 | } 138 | else 139 | { 140 | continue; 141 | } 142 | 143 | if(Math.abs(this.boundings[i].top - top) <= 4) 144 | { 145 | y = this.boundings[i].top; 146 | } 147 | else if(Math.abs(this.boundings[i].bottom - bottom) <= 4) 148 | { 149 | y = this.boundings[i].bottom - sizeY; 150 | } 151 | 152 | break; 153 | } 154 | } 155 | } 156 | 157 | this.element.style.left = x + "px"; 158 | this.element.style.top = y + "px"; 159 | this.element.style.transform = "translate(0px)"; 160 | 161 | this.position.x = x; 162 | this.position.y = y; 163 | }; 164 | 165 | DialogUI.prototype.size = function(width, height) 166 | { 167 | this.element.style.width = width + "px"; 168 | this.element.style.height = height + "px"; 169 | 170 | this.position.width = width; 171 | this.position.height = height; 172 | }; 173 | 174 | DialogUI.prototype.focus = function() 175 | { 176 | let zIndex = 1; 177 | 178 | let elements = document.querySelectorAll(".dialog"); 179 | 180 | for(let i = 0; i < elements.length; i++) 181 | { 182 | if(this.element == elements[i]) 183 | continue; 184 | 185 | if(elements[i].style.zIndex && parseInt(elements[i].style.zIndex) >= zIndex) 186 | zIndex = parseInt(elements[i].style.zIndex) + 1; 187 | } 188 | 189 | if(!this.element.style.zIndex || parseInt(this.element.style.zIndex) < zIndex) 190 | this.element.style.zIndex = zIndex.toString(); 191 | }; 192 | 193 | DialogUI.prototype.checkPosition = function() 194 | { 195 | if(this.position.x !== undefined && this.position.y !== undefined) 196 | { 197 | let x = this.position.x; 198 | let y = this.position.y; 199 | 200 | this.move(x, y); 201 | 202 | this.position.x = x; 203 | this.position.y = y; 204 | } 205 | }; 206 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/createdialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function CreateDialogUI(parent, title, text, x, y, clickAccept, clickCancel) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.appendStaticText("Text"); 7 | this.contentUI.appendLineBreak(); 8 | this.textUI = new TextBoxUI(this.contentUI, {value: text}); 9 | this.contentUI.appendLineBreak(); 10 | this.contentUI.appendStaticText("Position"); 11 | this.contentUI.appendLineBreak(); 12 | this.xUI = new TextBoxUI(this.contentUI, {value: x.toPlainString(), class: "textBoxLeft"}); 13 | this.yUI = new TextBoxUI(this.contentUI, {value: y.toPlainString(), class: "textBoxRight"}); 14 | this.contentUI.appendStaticLine(); 15 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Accept", click: () => { clickAccept(this.textUI.element.value, parseFloat(this.xUI.element.value), parseFloat(this.yUI.element.value)); }}); 16 | this.buttonCancelUI = new ButtonUI(this.buttonsUI, {innerText: "Cancel", click: () => { clickCancel(); }}); 17 | 18 | this.element.style.width = "260px"; 19 | this.element.style.minWidth = this.element.style.width; 20 | this.element.style.minHeight = this.element.clientHeight + "px"; 21 | this.element.style.maxHeight = this.element.style.minHeight; 22 | } 23 | 24 | CreateDialogUI.prototype = Object.create(DialogUI.prototype); 25 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/exportdialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function ExportDialogUI(parent, title, exportType, clickAccept, clickCancel) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | if(exportType == "json") 7 | { 8 | this.contentUI.appendStaticText("JSON Formatter"); 9 | this.contentUI.appendLineBreak(); 10 | this.callbackUI = new ListBoxUI(this.contentUI, {change: (e) => { this.changeOption(clickAccept); }}); 11 | this.callbackUI.appendOption("Pretty JSON"); 12 | this.callbackUI.appendOption("Minify JSON"); 13 | } 14 | else if(exportType == "pawn") 15 | { 16 | this.contentUI.appendStaticText("Callback"); 17 | this.contentUI.appendLineBreak(); 18 | this.callbackUI = new ListBoxUI(this.contentUI, {change: (e) => { this.changeOption(clickAccept); }}); 19 | this.callbackUI.appendOption("OnGameModeInit"); 20 | this.callbackUI.appendOption("OnFilterScriptInit"); 21 | } 22 | 23 | this.contentUI.appendLineBreak(); 24 | this.contentUI.appendStaticText("Output"); 25 | this.contentUI.appendLineBreak(); 26 | this.outputUI = new ListBoxUI(this.contentUI, {change: (e) => { this.changeOption(clickAccept); }}); 27 | this.outputUI.appendOption("Save output to a file"); 28 | this.outputUI.appendOption("View output as text"); 29 | this.contentUI.appendStaticLine(); 30 | this.viewOutputUI = null; 31 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Accept", click: () => { clickAccept(this.callbackUI.element.selectedIndex, this.outputUI.element.selectedIndex, true); }}); 32 | this.buttonCancelUI = new ButtonUI(this.buttonsUI, {innerText: "Cancel", click: () => { clickCancel(); }}); 33 | 34 | this.element.style.width = "260px"; 35 | this.element.style.minWidth = this.element.style.width; 36 | this.element.style.minHeight = this.element.clientHeight + "px"; 37 | this.element.style.maxHeight = this.element.style.minHeight; 38 | } 39 | 40 | ExportDialogUI.prototype = Object.create(DialogUI.prototype); 41 | 42 | ExportDialogUI.prototype.changeOption = function(clickAccept) 43 | { 44 | let oldWidth = this.element.offsetWidth; 45 | let oldHeight = this.element.offsetHeight; 46 | 47 | let callback = this.callbackUI.element.selectedIndex; 48 | let output = this.outputUI.element.selectedIndex; 49 | 50 | if(output == 0) 51 | { 52 | this.contentUI.element.style.display = ""; 53 | 54 | this.element.style.width = "260px"; 55 | this.element.style.height = ""; 56 | this.element.style.minWidth = this.element.style.width; 57 | this.element.style.minHeight = ""; 58 | this.element.style.maxHeight = ""; 59 | 60 | if(this.viewOutputUI) 61 | { 62 | this.callbackUI.element.style.width = ""; 63 | this.outputUI.element.style.width = ""; 64 | 65 | if(this.viewOutputUI.element.nextSibling && this.viewOutputUI.element.nextSibling.entityUI) 66 | this.viewOutputUI.element.nextSibling.entityUI.remove(); 67 | 68 | this.viewOutputUI.remove(); 69 | this.viewOutputUI = null; 70 | } 71 | 72 | this.element.style.minHeight = this.element.clientHeight + "px"; 73 | this.element.style.maxHeight = this.element.style.minHeight; 74 | } 75 | else 76 | { 77 | this.contentUI.element.style.display = "flex"; 78 | 79 | this.element.style.width = "460px"; 80 | this.element.style.height = ""; 81 | this.element.style.minWidth = this.element.style.width; 82 | this.element.style.minHeight = ""; 83 | this.element.style.maxHeight = ""; 84 | 85 | if(!this.viewOutputUI) 86 | { 87 | this.viewOutputUI = new EntityUI(this.contentUI, "textarea", {}); 88 | this.contentUI.appendStaticLine(); 89 | } 90 | 91 | this.element.style.minHeight = this.element.clientHeight + "px"; 92 | this.element.style.maxHeight = ""; 93 | 94 | clickAccept(callback, output, false); 95 | } 96 | 97 | let newWidth = this.element.offsetWidth; 98 | let newHeight = this.element.offsetHeight; 99 | 100 | if(oldWidth != newWidth || oldHeight != newHeight) 101 | this.move(this.element.offsetLeft + (oldWidth - newWidth) / 2, this.element.offsetTop + (oldHeight - newHeight) / 2); 102 | }; 103 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/guidegriddialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function GuideGridDialogUI(parent, title, x, y, width, height, margin, padding, rows, columns, clickAccept, clickCancel) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.appendStaticText("Position"); 7 | this.contentUI.appendLineBreak(); 8 | this.xUI = new TextBoxUI(this.contentUI, {value: x.toPlainString(), class: "textBoxLeft"}); 9 | this.yUI = new TextBoxUI(this.contentUI, {value: y.toPlainString(), class: "textBoxRight"}); 10 | this.contentUI.appendLineBreak(); 11 | this.contentUI.appendStaticText("Size"); 12 | this.contentUI.appendLineBreak(); 13 | this.widthUI = new TextBoxUI(this.contentUI, {value: width.toPlainString(), class: "textBoxLeft"}); 14 | this.heightUI = new TextBoxUI(this.contentUI, {value: height.toPlainString(), class: "textBoxRight"}); 15 | this.contentUI.appendLineBreak(); 16 | this.contentUI.appendStaticText("Margin / Padding"); 17 | this.contentUI.appendLineBreak(); 18 | this.marginUI = new TextBoxUI(this.contentUI, {value: margin.toPlainString(), class: "textBoxLeft"}); 19 | this.paddingUI = new TextBoxUI(this.contentUI, {value: padding.toPlainString(), class: "textBoxRight"}); 20 | this.contentUI.appendLineBreak(); 21 | this.contentUI.appendStaticText("Rows / Columns"); 22 | this.contentUI.appendLineBreak(); 23 | this.rowsUI = new TextBoxUI(this.contentUI, {value: rows.toString(), class: "textBoxLeft"}); 24 | this.columnsUI = new TextBoxUI(this.contentUI, {value: columns.toString(), class: "textBoxRight"}); 25 | this.contentUI.appendStaticLine(); 26 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Accept", click: () => { clickAccept(parseFloat(this.xUI.element.value), parseFloat(this.yUI.element.value), parseFloat(this.widthUI.element.value), parseFloat(this.heightUI.element.value), parseFloat(this.marginUI.element.value), parseFloat(this.paddingUI.element.value), parseInt(this.rowsUI.element.value), parseInt(this.columnsUI.element.value)); }}); 27 | this.buttonCancelUI = new ButtonUI(this.buttonsUI, {innerText: "Cancel", click: () => { clickCancel(); }}); 28 | 29 | this.element.style.width = "260px"; 30 | this.element.style.minWidth = this.element.style.width; 31 | this.element.style.minHeight = this.element.clientHeight + "px"; 32 | this.element.style.maxHeight = this.element.style.minHeight; 33 | } 34 | 35 | GuideGridDialogUI.prototype = Object.create(DialogUI.prototype); 36 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/guidelinedialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function GuideLineDialogUI(parent, title, x, y, size, padding, style, clickAccept, clickCancel) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.appendStaticText("Position"); 7 | this.contentUI.appendLineBreak(); 8 | this.xUI = new TextBoxUI(this.contentUI, {value: x.toPlainString(), class: "textBoxLeft"}); 9 | this.yUI = new TextBoxUI(this.contentUI, {value: y.toPlainString(), class: "textBoxRight"}); 10 | this.contentUI.appendLineBreak(); 11 | this.contentUI.appendStaticText("Size"); 12 | this.contentUI.appendLineBreak(); 13 | this.sizeUI = new TextBoxUI(this.contentUI, {value: size.toPlainString()}); 14 | this.contentUI.appendLineBreak(); 15 | this.contentUI.appendStaticText("Padding"); 16 | this.contentUI.appendLineBreak(); 17 | this.paddingUI = new TextBoxUI(this.contentUI, {value: padding.toPlainString()}); 18 | this.contentUI.appendLineBreak(); 19 | this.contentUI.appendStaticText("Style"); 20 | this.contentUI.appendLineBreak(); 21 | this.styleUI = new ListBoxUI(this.contentUI, {}); 22 | this.styleUI.appendOption("Horizontal"); 23 | this.styleUI.appendOption("Vertical"); 24 | this.styleUI.element.selectedIndex = style; 25 | this.contentUI.appendStaticLine(); 26 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Accept", click: () => { clickAccept(parseFloat(this.xUI.element.value), parseFloat(this.yUI.element.value), parseFloat(this.sizeUI.element.value), parseFloat(this.paddingUI.element.value), this.styleUI.element.selectedIndex); }}); 27 | this.buttonCancelUI = new ButtonUI(this.buttonsUI, {innerText: "Cancel", click: () => { clickCancel(); }}); 28 | 29 | this.element.style.width = "260px"; 30 | this.element.style.minWidth = this.element.style.width; 31 | this.element.style.minHeight = this.element.clientHeight + "px"; 32 | this.element.style.maxHeight = this.element.style.minHeight; 33 | } 34 | 35 | GuideLineDialogUI.prototype = Object.create(DialogUI.prototype); 36 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/historydialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function HistoryDialogUI(parent, title, history, historyIdx, keepHistory, clickAccept, clickHistory, contextMenu, keepHistoryChange) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.element.style.display = "flex"; 7 | 8 | this.historyListUI = new EntityUI(this.contentUI, "div", {class: ["textDrawList", "resizable"], contextmenu: (e) => { contextMenu(e.clientX, e.clientY); e.preventDefault(); }}); 9 | 10 | this.keepHistoryLabelUI = new EntityUI(this.contentUI, "label", {}); 11 | this.keepHistoryCheckboxUI = new TextBoxUI(this.keepHistoryLabelUI, {type: "checkbox", checked: (keepHistory ? "checked" : ""), change: (e) => { keepHistoryChange(e); }}); 12 | this.keepHistoryLabelUI.appendStaticText("Keep history"); 13 | 14 | this.contentUI.appendStaticLine(); 15 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Close", click: () => { clickAccept(); }}); 16 | 17 | this.resizeObserver = new ResizeObserver(() => { this.sizeChanged(); }); 18 | this.resizeObserver.observe(this.historyListUI.element); 19 | 20 | this.currentHistoryItemUI = null; 21 | this.lastHistoryItemUI = null; 22 | 23 | this.updateHistoryList(history, historyIdx, clickHistory); 24 | 25 | this.element.style.width = "260px"; 26 | this.element.style.minWidth = this.element.style.width; 27 | this.element.style.minHeight = this.element.clientHeight + "px"; 28 | } 29 | 30 | HistoryDialogUI.prototype = Object.create(DialogUI.prototype); 31 | 32 | HistoryDialogUI.prototype.sizeChanged = function() 33 | { 34 | if(this.lastHistoryItemUI) 35 | { 36 | if(this.historyListUI.hasScrollBar()) 37 | { 38 | if(!this.lastHistoryItemUI.element.classList.contains("lastTextDrawItem")) 39 | this.lastHistoryItemUI.element.classList.add("lastTextDrawItem"); 40 | } 41 | else 42 | { 43 | if(this.lastHistoryItemUI.element.classList.contains("lastTextDrawItem")) 44 | this.lastHistoryItemUI.element.classList.remove("lastTextDrawItem"); 45 | } 46 | } 47 | 48 | if(this.position.width != this.element.clientWidth || this.position.height != this.element.clientHeight) 49 | { 50 | this.position.width = this.element.clientWidth; 51 | this.position.height = this.element.clientHeight; 52 | 53 | clearTimeout(this.saveSettingsTimeoutId); 54 | this.saveSettingsTimeoutId = setTimeout(() => main.saveSettings(), 200); 55 | } 56 | }; 57 | 58 | HistoryDialogUI.prototype.updateHistoryList = function(history, historyIdx, clickHistory) 59 | { 60 | let oldWidth = this.element.offsetWidth; 61 | let oldHeight = this.element.offsetHeight; 62 | 63 | this.historyListUI.element.innerHTML = ""; 64 | 65 | let historyItemUI = null; 66 | let currentHistoryItemUI = null; 67 | 68 | for(let i = 0; i < history.length; i++) 69 | { 70 | let historyData = history[i]; 71 | 72 | historyItemUI = new EntityUI(this.historyListUI, "div", {class: "textDrawItem", onclick: (e) => { clickHistory(historyData); this.updateStyles(e.currentTarget.entityUI); } }); 73 | historyItemUI.appendStaticText(historyData.type.name); 74 | 75 | if(i == historyIdx) 76 | { 77 | historyItemUI.element.classList.add("currentTextDrawItem"); 78 | currentHistoryItemUI = historyItemUI; 79 | } 80 | else if(i > historyIdx) 81 | { 82 | historyItemUI.element.firstChild.style.fontStyle = "italic"; 83 | historyItemUI.element.firstChild.style.color = "#777777"; 84 | } 85 | } 86 | 87 | if(this.historyListUI.hasScrollBar()) 88 | historyItemUI.element.classList.add("lastTextDrawItem"); 89 | 90 | if(currentHistoryItemUI) 91 | currentHistoryItemUI.element.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"}); 92 | 93 | this.currentHistoryItemUI = currentHistoryItemUI; 94 | this.lastHistoryItemUI = historyItemUI; 95 | 96 | let newWidth = this.element.offsetWidth; 97 | let newHeight = this.element.offsetHeight; 98 | 99 | if(oldWidth != newWidth || oldHeight != newHeight) 100 | this.move(this.element.offsetLeft + (oldWidth - newWidth) / 2, this.element.offsetTop + (oldHeight - newHeight) / 2); 101 | }; 102 | 103 | HistoryDialogUI.prototype.updateStyles = function(historyItemUI) 104 | { 105 | if(this.currentHistoryItemUI) 106 | { 107 | this.currentHistoryItemUI.element.classList.remove("currentTextDrawItem"); 108 | 109 | let element = this.currentHistoryItemUI.element.nextSibling; 110 | 111 | while(element) 112 | { 113 | element.firstChild.style.fontStyle = ""; 114 | element.firstChild.style.color = ""; 115 | 116 | element = element.nextSibling 117 | } 118 | } 119 | 120 | if(historyItemUI) 121 | { 122 | historyItemUI.element.classList.add("currentTextDrawItem"); 123 | 124 | let element = historyItemUI.element.nextSibling; 125 | 126 | while(element) 127 | { 128 | element.firstChild.style.fontStyle = "italic"; 129 | element.firstChild.style.color = "#777777"; 130 | 131 | element = element.nextSibling 132 | } 133 | } 134 | 135 | this.currentHistoryItemUI = historyItemUI; 136 | }; 137 | 138 | HistoryDialogUI.prototype.remove = function() 139 | { 140 | this.resizeObserver.disconnect(); 141 | DialogUI.prototype.remove.call(this); 142 | }; 143 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/importdialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function ImportDialogUI(parent, title, importType, clickAccept, clickCancel) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.appendStaticText("Input"); 7 | this.contentUI.appendLineBreak(); 8 | this.inputUI = new ListBoxUI(this.contentUI, {change: (e) => { this.changeOption(); }}); 9 | this.inputUI.appendOption("Load input from a file"); 10 | this.inputUI.appendOption("View input as text"); 11 | this.contentUI.appendStaticLine(); 12 | this.fileInputUI = new FileBoxUI(this.contentUI, {accept: "*/*", onchange: (e) => { this.inputFromAFile(e); }}); 13 | this.viewInputUI = null; 14 | this.contentUI.appendStaticLine(); 15 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Accept", click: () => { clickAccept(this.inputUI.element.selectedIndex); }}); 16 | this.buttonCancelUI = new ButtonUI(this.buttonsUI, {innerText: "Cancel", click: () => { clickCancel(); }}); 17 | 18 | this.importType = importType; 19 | 20 | this.savedData = ""; 21 | this.textDraws = []; 22 | 23 | this.element.style.width = "260px"; 24 | this.element.style.minWidth = this.element.style.width; 25 | this.element.style.minHeight = this.element.clientHeight + "px"; 26 | this.element.style.maxHeight = this.element.style.minHeight; 27 | } 28 | 29 | ImportDialogUI.prototype = Object.create(DialogUI.prototype); 30 | 31 | ImportDialogUI.prototype.changeOption = function() 32 | { 33 | let oldWidth = this.element.offsetWidth; 34 | let oldHeight = this.element.offsetHeight; 35 | 36 | let input = this.inputUI.element.selectedIndex; 37 | 38 | if(input == 0) 39 | { 40 | this.contentUI.element.style.display = ""; 41 | 42 | this.element.style.width = "260px"; 43 | this.element.style.height = ""; 44 | this.element.style.minWidth = this.element.style.width; 45 | this.element.style.minHeight = ""; 46 | this.element.style.maxHeight = ""; 47 | 48 | if(!this.fileInputUI) 49 | { 50 | this.fileInputUI = new FileBoxUI(this.contentUI, {accept: "*/*", onchange: (e) => { this.inputFromAFile(e); }}); 51 | this.contentUI.appendStaticLine(); 52 | } 53 | 54 | if(this.viewInputUI) 55 | { 56 | this.inputUI.element.style.width = ""; 57 | 58 | if(this.viewInputUI.element.nextSibling && this.viewInputUI.element.nextSibling.entityUI) 59 | this.viewInputUI.element.nextSibling.entityUI.remove(); 60 | 61 | this.viewInputUI.remove(); 62 | this.viewInputUI = null; 63 | 64 | this.savedData = ""; 65 | this.textDraws = []; 66 | } 67 | 68 | this.element.style.minHeight = this.element.clientHeight + "px"; 69 | this.element.style.maxHeight = this.element.style.minHeight; 70 | } 71 | else 72 | { 73 | this.contentUI.element.style.display = "flex"; 74 | 75 | this.element.style.width = "460px"; 76 | this.element.style.height = ""; 77 | this.element.style.minWidth = this.element.style.width; 78 | this.element.style.minHeight = ""; 79 | this.element.style.maxHeight = ""; 80 | 81 | if(this.fileInputUI) 82 | { 83 | if(this.fileInputUI.element.nextSibling && this.fileInputUI.element.nextSibling.entityUI) 84 | this.fileInputUI.element.nextSibling.entityUI.remove(); 85 | 86 | this.fileInputUI.remove(); 87 | this.fileInputUI = null; 88 | 89 | this.savedData = ""; 90 | this.textDraws = []; 91 | } 92 | 93 | if(!this.viewInputUI) 94 | { 95 | this.viewInputUI = new EntityUI(this.contentUI, "textarea", {}); 96 | this.contentUI.appendStaticLine(); 97 | } 98 | 99 | this.element.style.minHeight = this.element.clientHeight + "px"; 100 | this.element.style.maxHeight = ""; 101 | } 102 | 103 | let newWidth = this.element.offsetWidth; 104 | let newHeight = this.element.offsetHeight; 105 | 106 | if(oldWidth != newWidth || oldHeight != newHeight) 107 | this.move(this.element.offsetLeft + (oldWidth - newWidth) / 2, this.element.offsetTop + (oldHeight - newHeight) / 2); 108 | }; 109 | 110 | ImportDialogUI.prototype.inputAsText = function(text) 111 | { 112 | this.textDraws = []; 113 | 114 | let lines = text.match(/[^\r\n]+/g); 115 | 116 | for(let i = 0; i < lines.length; i++) 117 | { 118 | let name = ""; 119 | let line = lines[i]; 120 | 121 | let matches = [...line.matchAll(/([^\=]+)\=([^;]+);/g)]; 122 | 123 | if(matches.length != 0) 124 | { 125 | name = matches[0][1].trim().split(" ").filter(n => n).pop().split(":").pop(); 126 | line = matches[0][2].trim(); 127 | } 128 | 129 | matches = [...line.matchAll(/([^\(]+)\(([^\)]+)\)/g)]; 130 | 131 | if(matches.length != 0) 132 | { 133 | let func = matches[0][1].trim(); 134 | let params = this.splitParams(matches[0][2]); 135 | 136 | if(func == "TextDrawCreate") 137 | { 138 | if(name.length != 0 && params.length == 3) 139 | { 140 | let paramX = Number(params[0]); 141 | let paramY = Number(params[1]); 142 | let paramText = JSON.parse(params[2]); 143 | 144 | if(typeof paramX == "number" && typeof paramY == "number" && typeof paramText == "string") 145 | { 146 | let textDraw = {}; 147 | 148 | textDraw.name = name; 149 | textDraw.text = paramText; 150 | textDraw.x = paramX; 151 | textDraw.y = paramY; 152 | textDraw.letterSizeX = 0.48; 153 | textDraw.letterSizeY = 1.12; 154 | textDraw.textSizeX = 1280.0; 155 | textDraw.textSizeY = 1280.0; 156 | textDraw.alignment = 1; 157 | textDraw.color = 0xE1E1E1FF; 158 | textDraw.useBox = 0; 159 | textDraw.boxColor = 0x80808080; 160 | textDraw.setShadow = 2; 161 | textDraw.setOutline = 0; 162 | textDraw.backgroundColor = 0x000000FF; 163 | textDraw.font = 1; 164 | textDraw.setProportional = 1; 165 | 166 | this.textDraws.push(textDraw); 167 | } 168 | } 169 | } 170 | else if(func == "TextDrawLetterSize") 171 | { 172 | if(params.length == 3) 173 | { 174 | let paramName = params[0]; 175 | let paramLetterSizeX = Number(params[1]); 176 | let paramLetterSizeY = Number(params[2]); 177 | 178 | if(typeof paramLetterSizeX == "number" && typeof paramLetterSizeY == "number") 179 | { 180 | let textDraw = this.getTextDrawAt(paramName); 181 | 182 | if(textDraw) 183 | { 184 | textDraw.letterSizeX = paramLetterSizeX; 185 | textDraw.letterSizeY = paramLetterSizeY; 186 | } 187 | } 188 | } 189 | } 190 | else if(func == "TextDrawTextSize") 191 | { 192 | if(params.length == 3) 193 | { 194 | let paramName = params[0]; 195 | let paramTextSizeX = Number(params[1]); 196 | let paramTextSizeY = Number(params[2]); 197 | 198 | if(typeof paramTextSizeX == "number" && typeof paramTextSizeY == "number") 199 | { 200 | let textDraw = this.getTextDrawAt(paramName); 201 | 202 | if(textDraw) 203 | { 204 | textDraw.textSizeX = paramTextSizeX; 205 | textDraw.textSizeY = paramTextSizeY; 206 | } 207 | } 208 | } 209 | } 210 | else if(func == "TextDrawAlignment") 211 | { 212 | if(params.length == 2) 213 | { 214 | let paramName = params[0]; 215 | let paramAlignment = Number(params[1]); 216 | 217 | if(typeof paramAlignment == "number") 218 | { 219 | let textDraw = this.getTextDrawAt(paramName); 220 | 221 | if(textDraw) 222 | textDraw.alignment = paramAlignment; 223 | } 224 | } 225 | } 226 | else if(func == "TextDrawColor") 227 | { 228 | if(params.length == 2) 229 | { 230 | let paramName = params[0]; 231 | let paramColor = Number(params[1]); 232 | 233 | if(typeof paramColor == "number") 234 | { 235 | let textDraw = this.getTextDrawAt(paramName); 236 | 237 | if(textDraw) 238 | textDraw.color = paramColor; 239 | } 240 | } 241 | } 242 | else if(func == "TextDrawUseBox") 243 | { 244 | if(params.length == 2) 245 | { 246 | let paramName = params[0]; 247 | let paramUseBox = Number(params[1]); 248 | 249 | if(typeof paramUseBox == "number") 250 | { 251 | let textDraw = this.getTextDrawAt(paramName); 252 | 253 | if(textDraw) 254 | textDraw.useBox = paramUseBox; 255 | } 256 | } 257 | } 258 | else if(func == "TextDrawBoxColor") 259 | { 260 | if(params.length == 2) 261 | { 262 | let paramName = params[0]; 263 | let paramBoxColor = Number(params[1]); 264 | 265 | if(typeof paramBoxColor == "number") 266 | { 267 | let textDraw = this.getTextDrawAt(paramName); 268 | 269 | if(textDraw) 270 | textDraw.boxColor = paramBoxColor; 271 | } 272 | } 273 | } 274 | else if(func == "TextDrawSetShadow") 275 | { 276 | if(params.length == 2) 277 | { 278 | let paramName = params[0]; 279 | let paramSetShadow = Number(params[1]); 280 | 281 | if(typeof paramSetShadow == "number") 282 | { 283 | let textDraw = this.getTextDrawAt(paramName); 284 | 285 | if(textDraw) 286 | textDraw.setShadow = paramSetShadow; 287 | } 288 | } 289 | } 290 | else if(func == "TextDrawSetOutline") 291 | { 292 | if(params.length == 2) 293 | { 294 | let paramName = params[0]; 295 | let paramSetOutline = Number(params[1]); 296 | 297 | if(typeof paramSetOutline == "number") 298 | { 299 | let textDraw = this.getTextDrawAt(paramName); 300 | 301 | if(textDraw) 302 | textDraw.setOutline = paramSetOutline; 303 | } 304 | } 305 | } 306 | else if(func == "TextDrawBackgroundColor") 307 | { 308 | if(params.length == 2) 309 | { 310 | let paramName = params[0]; 311 | let paramBackgroundColor = Number(params[1]); 312 | 313 | if(typeof paramBackgroundColor == "number") 314 | { 315 | let textDraw = this.getTextDrawAt(paramName); 316 | 317 | if(textDraw) 318 | textDraw.backgroundColor = paramBackgroundColor; 319 | } 320 | } 321 | } 322 | else if(func == "TextDrawFont") 323 | { 324 | if(params.length == 2) 325 | { 326 | let paramName = params[0]; 327 | let paramFont = Number(params[1]); 328 | 329 | if(params[1] == "TEXT_DRAW_FONT_SPRITE_DRAW") 330 | { 331 | paramFont = 4; 332 | } 333 | else if(params[1] == "TEXT_DRAW_FONT_MODEL_PREVIEW") 334 | { 335 | paramFont = 5; 336 | } 337 | 338 | if(typeof paramFont == "number") 339 | { 340 | let textDraw = this.getTextDrawAt(paramName); 341 | 342 | if(textDraw) 343 | textDraw.font = paramFont; 344 | } 345 | } 346 | } 347 | else if(func == "TextDrawSetProportional") 348 | { 349 | if(params.length == 2) 350 | { 351 | let paramName = params[0]; 352 | let paramSetProportional = Number(params[1]); 353 | 354 | if(typeof paramSetProportional == "number") 355 | { 356 | let textDraw = this.getTextDrawAt(paramName); 357 | 358 | if(textDraw) 359 | textDraw.setProportional = paramSetProportional; 360 | } 361 | } 362 | } 363 | } 364 | } 365 | }; 366 | 367 | ImportDialogUI.prototype.inputFromAFile = function(e) 368 | { 369 | let files = e.target.files; 370 | 371 | if(files.length != 0) 372 | { 373 | let file = files[0]; 374 | 375 | let reader = new FileReader(); 376 | 377 | reader.onload = (e) => 378 | { 379 | if(e.target.readyState == FileReader.DONE) 380 | { 381 | if(this.importType == "json") 382 | { 383 | this.savedData = e.target.result; 384 | } 385 | else if(this.importType == "pawn") 386 | { 387 | this.inputAsText(e.target.result); 388 | } 389 | } 390 | }; 391 | 392 | reader.readAsText(file); 393 | } 394 | }; 395 | 396 | ImportDialogUI.prototype.splitParams = function(text) 397 | { 398 | let params = []; 399 | let param = ""; 400 | 401 | let isEscape = false; 402 | let isDoubleQuote = false; 403 | let isSingleQuote = false; 404 | 405 | for(let i = 0; i < text.length; i++) 406 | { 407 | let chr = text.charAt(i); 408 | 409 | if(isEscape) 410 | { 411 | param += chr; 412 | 413 | isEscape = false; 414 | continue; 415 | } 416 | 417 | if(isDoubleQuote) 418 | { 419 | param += chr; 420 | 421 | if(chr == '"') 422 | isDoubleQuote = false; 423 | 424 | continue; 425 | } 426 | 427 | if(isSingleQuote) 428 | { 429 | param += chr; 430 | 431 | isSingleQuote = false; 432 | continue; 433 | } 434 | 435 | if(chr == '"') 436 | { 437 | param += chr; 438 | 439 | isDoubleQuote = true; 440 | continue; 441 | } 442 | 443 | if(chr == '\'') 444 | { 445 | param += chr; 446 | 447 | isSingleQuote = true; 448 | continue; 449 | } 450 | 451 | if(chr == ',') 452 | { 453 | param = param.trim(); 454 | 455 | if(param.length != 0) 456 | { 457 | params.push(param); 458 | param = ""; 459 | } 460 | 461 | continue; 462 | } 463 | 464 | param += chr; 465 | } 466 | 467 | param = param.trim(); 468 | 469 | if(param.length != 0) 470 | params.push(param); 471 | 472 | return params; 473 | }; 474 | 475 | ImportDialogUI.prototype.getTextDrawAt = function(name) 476 | { 477 | for(let i = 0; i < this.textDraws.length; i++) 478 | { 479 | if(this.textDraws[i].name == name) 480 | return this.textDraws[i]; 481 | } 482 | 483 | return null; 484 | }; 485 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/multipleselectiondialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function MultipleSelectionDialogUI(parent, title, x, y, width, height, clickAccept, clickCancel) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.appendStaticText("Position"); 7 | this.contentUI.appendLineBreak(); 8 | this.xUI = new TextBoxUI(this.contentUI, {value: x.toPlainString(), class: "textBoxLeft"}); 9 | this.yUI = new TextBoxUI(this.contentUI, {value: y.toPlainString(), class: "textBoxRight"}); 10 | this.contentUI.appendLineBreak(); 11 | this.contentUI.appendStaticText("Size"); 12 | this.contentUI.appendLineBreak(); 13 | this.widthUI = new TextBoxUI(this.contentUI, {value: width.toPlainString(), class: "textBoxLeft"}); 14 | this.heightUI = new TextBoxUI(this.contentUI, {value: height.toPlainString(), class: "textBoxRight"}); 15 | this.contentUI.appendStaticLine(); 16 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Accept", click: () => { clickAccept(parseFloat(this.xUI.element.value), parseFloat(this.yUI.element.value), parseFloat(this.widthUI.element.value), parseFloat(this.heightUI.element.value)); }}); 17 | this.buttonCancelUI = new ButtonUI(this.buttonsUI, {innerText: "Cancel", click: () => { clickCancel(); }}); 18 | 19 | this.element.style.width = "260px"; 20 | this.element.style.minWidth = this.element.style.width; 21 | this.element.style.minHeight = this.element.clientHeight + "px"; 22 | this.element.style.maxHeight = this.element.style.minHeight; 23 | } 24 | 25 | MultipleSelectionDialogUI.prototype = Object.create(DialogUI.prototype); 26 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/textdrawlistdialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function TextDrawListDialogUI(parent, title, textDrawListUI, clickAccept) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.element.style.display = "flex"; 7 | this.contentUI.element.appendChild(textDrawListUI.element); 8 | 9 | this.textDrawListUI = textDrawListUI; 10 | 11 | this.contentUI.appendStaticLine(); 12 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Close", click: () => { clickAccept(); }}); 13 | 14 | this.resizeObserver = new ResizeObserver(() => { this.sizeChanged(); }); 15 | this.resizeObserver.observe(textDrawListUI.element); 16 | 17 | this.element.style.width = "260px"; 18 | this.element.style.minWidth = this.element.style.width; 19 | this.element.style.minHeight = this.element.clientHeight + "px"; 20 | } 21 | 22 | TextDrawListDialogUI.prototype = Object.create(DialogUI.prototype); 23 | 24 | TextDrawListDialogUI.prototype.sizeChanged = function() 25 | { 26 | if(this.textDrawListUI.lastTextDrawItemUI) 27 | { 28 | if(this.textDrawListUI.hasScrollBar()) 29 | { 30 | if(!this.textDrawListUI.lastTextDrawItemUI.element.classList.contains("lastTextDrawItem")) 31 | this.textDrawListUI.lastTextDrawItemUI.element.classList.add("lastTextDrawItem"); 32 | } 33 | else 34 | { 35 | if(this.textDrawListUI.lastTextDrawItemUI.element.classList.contains("lastTextDrawItem")) 36 | this.textDrawListUI.lastTextDrawItemUI.element.classList.remove("lastTextDrawItem"); 37 | } 38 | } 39 | 40 | if(this.position.width != this.element.clientWidth || this.position.height != this.element.clientHeight) 41 | { 42 | this.position.width = this.element.clientWidth; 43 | this.position.height = this.element.clientHeight; 44 | 45 | clearTimeout(this.saveSettingsTimeoutId); 46 | this.saveSettingsTimeoutId = setTimeout(() => main.saveSettings(), 200); 47 | } 48 | }; 49 | 50 | TextDrawListDialogUI.prototype.remove = function() 51 | { 52 | this.resizeObserver.disconnect(); 53 | DialogUI.prototype.remove.call(this); 54 | }; 55 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/texturedictionarydialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function TextureDictionaryDialogUI(parent, title, clickAccept, clickExplorer) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.element.style.display = "flex"; 7 | 8 | this.txdListUI = new EntityUI(this.contentUI, "div", {class: "textDrawList"}); 9 | this.fileInputUI = new FileBoxUI(this.contentUI, {accept: ".txd", multiple: "multiple", onchange: (e) => { this.loadTxd(e); }}); 10 | this.contentUI.appendStaticLine(); 11 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Close", click: () => { clickAccept(); }}); 12 | 13 | this.resizeObserver = new ResizeObserver(() => { this.sizeChanged(); }); 14 | this.resizeObserver.observe(this.txdListUI.element); 15 | 16 | this.lastTxdItemUI = null; 17 | 18 | this.updateTxdListBind = this.updateTxdList.bind(this, clickExplorer); 19 | 20 | TextureDictionary.updateEventListeners.push(this.updateTxdListBind); 21 | 22 | this.updateTxdList(clickExplorer); 23 | 24 | this.element.style.width = "260px"; 25 | this.element.style.minWidth = this.element.style.width; 26 | this.element.style.minHeight = this.element.clientHeight + "px"; 27 | } 28 | 29 | TextureDictionaryDialogUI.prototype = Object.create(DialogUI.prototype); 30 | 31 | TextureDictionaryDialogUI.prototype.sizeChanged = function() 32 | { 33 | if(this.lastTxdItemUI) 34 | { 35 | if(this.txdListUI.hasScrollBar()) 36 | { 37 | if(!this.lastTxdItemUI.element.classList.contains("lastTextDrawItem")) 38 | this.lastTxdItemUI.element.classList.add("lastTextDrawItem"); 39 | } 40 | else 41 | { 42 | if(this.lastTxdItemUI.element.classList.contains("lastTextDrawItem")) 43 | this.lastTxdItemUI.element.classList.remove("lastTextDrawItem"); 44 | } 45 | } 46 | 47 | if(this.position.width != this.element.clientWidth || this.position.height != this.element.clientHeight) 48 | { 49 | this.position.width = this.element.clientWidth; 50 | this.position.height = this.element.clientHeight; 51 | 52 | clearTimeout(this.saveSettingsTimeoutId); 53 | this.saveSettingsTimeoutId = setTimeout(() => main.saveSettings(), 200); 54 | } 55 | }; 56 | 57 | TextureDictionaryDialogUI.prototype.loadTxd = function(e) 58 | { 59 | let files = e.target.files; 60 | 61 | for(let i = 0; i < files.length; i++) 62 | { 63 | if(files[i].name.toLowerCase().endsWith(".txd")) 64 | { 65 | let name = files[i].name.toLowerCase().slice(0, -4); 66 | 67 | if(TextureDictionary.instances.find(textureDictionary => textureDictionary.name == name)) 68 | { 69 | alert(name + " is already loaded"); 70 | continue; 71 | } 72 | 73 | let reader = new FileReader(); 74 | 75 | reader.onload = (e) => 76 | { 77 | if(e.target.readyState == FileReader.DONE) 78 | TextureDictionary.newInstance(name, new Uint8Array(e.target.result)); 79 | }; 80 | 81 | reader.readAsArrayBuffer(files[i]); 82 | } 83 | else 84 | { 85 | alert("not an .txd"); 86 | } 87 | } 88 | 89 | this.fileInputUI.element.value = ""; 90 | }; 91 | 92 | TextureDictionaryDialogUI.prototype.updateTxdList = function(clickExplorer) 93 | { 94 | let oldWidth = this.element.offsetWidth; 95 | let oldHeight = this.element.offsetHeight; 96 | 97 | this.txdListUI.element.innerHTML = ""; 98 | 99 | let txdItemUI = null; 100 | 101 | for(let i = 0; i < TextureDictionary.instances.length; i++) 102 | { 103 | let textureDictionary = TextureDictionary.instances[i]; 104 | 105 | txdItemUI = new EntityUI(this.txdListUI, "div", {class: "textDrawItem", onclick: () => { clickExplorer(textureDictionary); } }); 106 | txdItemUI.appendStaticText(textureDictionary.name); 107 | } 108 | 109 | if(this.txdListUI.hasScrollBar()) 110 | txdItemUI.element.classList.add("lastTextDrawItem"); 111 | 112 | this.lastTxdItemUI = txdItemUI; 113 | 114 | let newWidth = this.element.offsetWidth; 115 | let newHeight = this.element.offsetHeight; 116 | 117 | if(oldWidth != newWidth || oldHeight != newHeight) 118 | this.move(this.element.offsetLeft + (oldWidth - newWidth) / 2, this.element.offsetTop + (oldHeight - newHeight) / 2); 119 | }; 120 | 121 | TextureDictionaryDialogUI.prototype.remove = function() 122 | { 123 | this.resizeObserver.disconnect(); 124 | TextureDictionary.updateEventListeners.splice(TextureDictionary.updateEventListeners.indexOf(this.updateTxdListBind), 1); 125 | DialogUI.prototype.remove.call(this); 126 | }; 127 | -------------------------------------------------------------------------------- /assets/js/ui/dialogui/textureexplorerdialogui.js: -------------------------------------------------------------------------------- 1 | 2 | function TextureExplorerDialogUI(parent, title, textureDictionary, clickAccept, contextMenu) 3 | { 4 | DialogUI.call(this, parent, title); 5 | 6 | this.contentUI.element.style.display = "flex"; 7 | 8 | this.texListUI = new EntityUI(this.contentUI, "div", {class: "textureList"}); 9 | this.infoUI = new EntityUI(this.contentUI, "span", {innerHTML: "ⓘ Press the right button on the mouse to copy."}); 10 | 11 | for(let i = 0; i < textureDictionary.textures.length; i++) 12 | { 13 | let texture = textureDictionary.textures[i]; 14 | let txdAndTexName = textureDictionary.name + ":" + texture.name; 15 | 16 | let texItemUI = new EntityUI(this.texListUI, "div", {class: "textureItem", title: txdAndTexName, contextmenu: (e) => { contextMenu(txdAndTexName, e.clientX, e.clientY); e.preventDefault(); }}); 17 | 18 | textureDictionary.textures[i].imageUI.element.toBlob((blob) => { new EntityUI(texItemUI, "img", {src: URL.createObjectURL(blob), width: 64, height: 64}); }); 19 | } 20 | 21 | this.contentUI.appendStaticLine(); 22 | this.buttonAcceptUI = new ButtonUI(this.buttonsUI, {innerText: "Close", click: () => { clickAccept(); }}); 23 | 24 | this.textureDictionary = textureDictionary; 25 | 26 | this.element.style.width = "460px"; 27 | this.element.style.minWidth = this.element.style.width; 28 | this.element.style.minHeight = this.element.clientHeight + "px"; 29 | } 30 | 31 | TextureExplorerDialogUI.prototype = Object.create(DialogUI.prototype); 32 | -------------------------------------------------------------------------------- /assets/js/ui/drawableui.js: -------------------------------------------------------------------------------- 1 | 2 | function DrawableUI(parent, setting) 3 | { 4 | EntityUI.call(this, parent, "canvas", setting); 5 | 6 | this.context = this.element.getContext("2d"); 7 | } 8 | 9 | DrawableUI.prototype = Object.create(EntityUI.prototype); 10 | -------------------------------------------------------------------------------- /assets/js/ui/drawableui/fontui.js: -------------------------------------------------------------------------------- 1 | 2 | function FontUI(parent, fontFile, setting) 3 | { 4 | DrawableUI.call(this, parent, setting); 5 | 6 | this.width = 0; 7 | this.height = 0; 8 | this.color = 0x00000000; 9 | 10 | this.imageUI = new EntityUI(null, "img", {"src": "./assets/images/font" + fontFile + ".png", onload: () => { this.resize(); }}); 11 | this.colorUI = new DrawableUI(null, {}); 12 | 13 | if(fontFile == 1) 14 | { 15 | this.prop = [ 15, 9, 17, 27, 20, 34, 23, 12, 12, 12, 21, 20, 12, 14, 12, 15, 23, 15, 21, 21, 21, 21, 21, 21, 20, 21, 12, 12, 24, 24, 24, 19, 10, 22, 19, 19, 22, 16, 19, 24, 22, 11, 16, 21, 15, 28, 24, 27, 20, 25, 19, 19, 18, 23, 23, 31, 23, 19, 21, 21, 13, 35, 11, 21, 10, 19, 20, 14, 20, 19, 13, 20, 19, 9, 9, 19, 9, 29, 19, 21, 19, 19, 15, 15, 14, 18, 19, 27, 20, 20, 17, 21, 17, 20, 15, 15, 22, 22, 22, 22, 29, 19, 16, 16, 16, 16, 11, 11, 11, 11, 27, 27, 27, 27, 23, 23, 23, 23, 20, 19, 19, 19, 19, 30, 14, 19, 19, 19, 19, 9, 9, 9, 9, 21, 21, 21, 21, 18, 18, 18, 18, 24, 19, 19, 20, 18, 19, 19, 21, 19, 19, 19, 19, 19, 16, 19, 19, 19, 20, 19, 16, 19, 19, 9, 19, 20, 14, 29, 19, 19, 19, 19, 19, 19, 21, 19, 20, 32, 21, 19, 19, 19, 19, 19, 19, 29, 19, 19, 19, 19, 19, 9, 9, 9, 9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 21, 19, 10, 9 ]; 16 | this.unprop = 27; 17 | } 18 | else 19 | { 20 | this.prop = [ 12, 13, 13, 28, 28, 28, 28, 8, 17, 17, 30, 28, 28, 12, 9, 21, 28, 14, 28, 28, 28, 28, 28, 28, 28, 28, 13, 13, 30, 30, 30, 30, 10, 25, 23, 21, 24, 22, 20, 24, 24, 17, 20, 22, 20, 30, 27, 27, 26, 26, 24, 23, 24, 31, 23, 31, 24, 23, 21, 28, 33, 33, 14, 28, 10, 11, 12, 9, 11, 10, 10, 12, 12, 7, 7, 13, 5, 18, 12, 10, 12, 11, 10, 12, 8, 13, 13, 18, 17, 13, 12, 30, 30, 37, 35, 37, 25, 25, 25, 25, 33, 21, 24, 24, 24, 24, 17, 17, 17, 17, 27, 27, 27, 27, 31, 31, 31, 31, 11, 11, 11, 11, 11, 20, 9, 10, 10, 10, 10, 7, 7, 7, 7, 10, 10, 10, 10, 13, 13, 13, 13, 27, 12, 30, 27, 16, 27, 27, 27, 27, 27, 27, 27, 27, 18, 29, 26, 25, 28, 26, 25, 27, 28, 12, 24, 25, 24, 30, 27, 29, 26, 26, 25, 26, 25, 26, 28, 32, 27, 26, 26, 29, 29, 29, 29, 33, 25, 26, 26, 26, 26, 14, 14, 14, 14, 29, 29, 29, 29, 26, 26, 26, 26, 21, 25, 30, 27, 27 ]; 21 | this.unprop = 20; 22 | } 23 | } 24 | 25 | FontUI.prototype = Object.create(DrawableUI.prototype); 26 | 27 | FontUI.prototype.resize = function() 28 | { 29 | this.width = this.imageUI.element.width; 30 | this.height = this.imageUI.element.height; 31 | 32 | if(this.width != this.element.width || this.height != this.element.height) 33 | { 34 | this.element.width = this.width; 35 | this.element.height = this.height; 36 | 37 | this.colorUI.element.width = this.width; 38 | this.colorUI.element.height = this.height; 39 | 40 | if(this.repaint !== undefined) 41 | this.repaint(); 42 | } 43 | }; 44 | 45 | FontUI.prototype.setColor = function(color) 46 | { 47 | this.color = color; 48 | 49 | this.colorUI.context.clearRect(0, 0, this.width, this.height); 50 | this.colorUI.context.fillStyle = color.toRGBA(); 51 | this.colorUI.context.fillRect(0, 0, this.width, this.height); 52 | this.colorUI.context.globalCompositeOperation = "destination-in"; 53 | this.colorUI.context.drawImage(this.imageUI.element, 0, 0, this.width, this.height, 0, 0, this.width, this.height); 54 | this.colorUI.context.globalCompositeOperation = "source-over"; 55 | }; 56 | 57 | FontUI.prototype.setColorLighter = function() 58 | { 59 | let color = this.color; 60 | 61 | let red = (color >> 24) & 0xFF; 62 | let green = (color >> 16) & 0xFF; 63 | let blue = (color >> 8) & 0xFF; 64 | let alpha = color & 0xFF; 65 | 66 | red = (red * 1.5) >>> 0; 67 | green = (green * 1.5) >>> 0; 68 | blue = (blue * 1.5) >>> 0; 69 | 70 | red = Math.min(red, 255); 71 | green = Math.min(green, 255); 72 | blue = Math.min(blue, 255); 73 | 74 | color = ((red << 24) + (green << 16) + (blue << 8) + (alpha)) >>> 0; 75 | 76 | this.setColor(color); 77 | }; 78 | -------------------------------------------------------------------------------- /assets/js/ui/drawableui/optionsui.js: -------------------------------------------------------------------------------- 1 | 2 | function OptionsUI(parent, setting) 3 | { 4 | DrawableUI.call(this, parent, setting); 5 | 6 | this.width = 0; 7 | this.height = 0; 8 | 9 | this.rectLeft = 0; 10 | this.rectTop = 0; 11 | this.rectRight = 0; 12 | this.rectBottom = 0; 13 | 14 | this.resizeRectLeft = 0; 15 | this.resizeRectTop = 0; 16 | this.resizeRectRight = 0; 17 | this.resizeRectBottom = 0; 18 | 19 | this.moveRectLeft = 0; 20 | this.moveRectTop = 0; 21 | this.moveRectRight = 0; 22 | this.moveRectBottom = 0; 23 | 24 | this.resizeLetterRectLeft = 0; 25 | this.resizeLetterRectTop = 0; 26 | this.resizeLetterRectRight = 0; 27 | this.resizeLetterRectBottom = 0; 28 | 29 | this.imageResizeUI = new EntityUI(null, "img", {"src": "./assets/images/resize.png", onload: () => { this.imageLoaded(); }}); 30 | this.imageMoveUI = new EntityUI(null, "img", {"src": "./assets/images/move.png", onload: () => { this.imageLoaded(); }}); 31 | this.imageResizeLetterUI = new EntityUI(null, "img", {"src": "./assets/images/resize-letter.png", onload: () => { this.imageLoaded(); }}); 32 | } 33 | 34 | OptionsUI.prototype = Object.create(DrawableUI.prototype); 35 | 36 | OptionsUI.prototype.imageLoaded = function() 37 | { 38 | if(this.imageResizeUI.element.complete && this.imageMoveUI.element.complete && this.imageResizeLetterUI.element.complete) 39 | { 40 | if(this.repaint !== undefined) 41 | this.repaint(); 42 | } 43 | }; 44 | 45 | OptionsUI.prototype.resize = function(width, height) 46 | { 47 | this.width = width; 48 | this.height = height; 49 | 50 | this.element.width = width; 51 | this.element.height = height; 52 | }; 53 | 54 | OptionsUI.prototype.clear = function() 55 | { 56 | this.context.clearRect(0, 0, this.width, this.height); 57 | }; 58 | 59 | OptionsUI.prototype.paintGuideGrids = function(currentGuideGrid, guideGrids, option) 60 | { 61 | if(guideGrids.length == 0) 62 | return; 63 | 64 | let scaleX = guideGrids[0].main.screenshotUI.width / 640.0; 65 | let scaleY = guideGrids[0].main.screenshotUI.height / 448.0; 66 | 67 | for(let i = 0; i < guideGrids.length; i++) 68 | { 69 | let guideGrid = guideGrids[i]; 70 | 71 | if(guideGrid != currentGuideGrid && !guideGrid.visibility) 72 | continue; 73 | 74 | let horizontalLineCount = guideGrid.getHorizontalLineCount(); 75 | let verticalLineCount = guideGrid.getVerticalLineCount(); 76 | 77 | if(horizontalLineCount >= 0 && verticalLineCount > 0) 78 | { 79 | this.context.beginPath(); 80 | 81 | if(guideGrid == currentGuideGrid) 82 | { 83 | this.context.setLineDash([5]); 84 | } 85 | else 86 | { 87 | this.context.setLineDash([]); 88 | } 89 | 90 | let minX = Math.round(guideGrid.getVerticalLine(0) * scaleX); 91 | let maxX = Math.round(guideGrid.getVerticalLine(verticalLineCount - 1) * scaleX); 92 | 93 | for(let j = 0; j < horizontalLineCount; j++) 94 | { 95 | let line = Math.round(guideGrid.getHorizontalLine(j) * scaleY); 96 | 97 | this.context.moveTo(minX, line); 98 | this.context.lineTo(maxX, line); 99 | } 100 | 101 | let minY = Math.round(guideGrid.getHorizontalLine(0) * scaleY); 102 | let maxY = Math.round(guideGrid.getHorizontalLine(horizontalLineCount - 1) * scaleY); 103 | 104 | for(let j = 0; j < verticalLineCount; j++) 105 | { 106 | let line = Math.round(guideGrid.getVerticalLine(j) * scaleX); 107 | 108 | this.context.moveTo(line, minY); 109 | this.context.lineTo(line, maxY); 110 | } 111 | 112 | this.context.stroke(); 113 | 114 | if(guideGrid == currentGuideGrid) 115 | { 116 | this.context.fillStyle = "#000000"; 117 | 118 | for(let j = 0; j < horizontalLineCount; j++) 119 | { 120 | let line = Math.round(guideGrid.getHorizontalLine(j) * scaleY); 121 | 122 | this.context.fillRect(minX - 2, line - 2, 4, 4); 123 | this.context.fillRect(maxX - 2, line - 2, 4, 4); 124 | } 125 | 126 | for(let j = 1; j < (verticalLineCount - 1); j++) 127 | { 128 | let line = Math.round(guideGrid.getVerticalLine(j) * scaleX); 129 | 130 | this.context.fillRect(line - 2, minY - 2, 4, 4); 131 | this.context.fillRect(line - 2, maxY - 2, 4, 4); 132 | } 133 | } 134 | } 135 | } 136 | 137 | if(currentGuideGrid) 138 | { 139 | let left = currentGuideGrid.getRectLeft() * scaleX; 140 | let top = currentGuideGrid.getRectTop() * scaleY; 141 | let right = currentGuideGrid.getRectRight() * scaleX; 142 | let bottom = currentGuideGrid.getRectBottom() * scaleY; 143 | 144 | this.drawOptions(left, top, right, bottom, option, false); 145 | } 146 | }; 147 | 148 | OptionsUI.prototype.paintGuideLines = function(currentGuideLine, guideLines, option) 149 | { 150 | if(guideLines.length == 0) 151 | return; 152 | 153 | let scaleX = guideLines[0].main.screenshotUI.width / 640.0; 154 | let scaleY = guideLines[0].main.screenshotUI.height / 448.0; 155 | 156 | for(let i = 0; i < guideLines.length; i++) 157 | { 158 | let guideLine = guideLines[i]; 159 | 160 | if(guideLine != currentGuideLine && !guideLine.visibility) 161 | continue; 162 | 163 | this.context.beginPath(); 164 | 165 | if(guideLine == currentGuideLine) 166 | { 167 | this.context.setLineDash([5]); 168 | } 169 | else 170 | { 171 | this.context.setLineDash([]); 172 | } 173 | 174 | let x = guideLine.x * scaleX; 175 | let y = guideLine.y * scaleY; 176 | 177 | if(guideLine.style == 0) 178 | { 179 | this.context.moveTo(x, y); 180 | this.context.lineTo(x + guideLine.size * scaleX, y); 181 | } 182 | else 183 | { 184 | this.context.moveTo(x, y); 185 | this.context.lineTo(x, y + guideLine.size * scaleY); 186 | } 187 | 188 | this.context.stroke(); 189 | 190 | if(guideLine == currentGuideLine) 191 | { 192 | this.context.fillStyle = "#000000"; 193 | this.context.fillRect(x - 2, y - 2, 4, 4); 194 | 195 | if(guideLine.style == 0) 196 | { 197 | this.context.fillRect(x + guideLine.size * scaleX - 2, y - 2, 4, 4); 198 | } 199 | else 200 | { 201 | this.context.fillRect(x - 2, y + guideLine.size * scaleY - 2, 4, 4); 202 | } 203 | } 204 | } 205 | 206 | if(currentGuideLine) 207 | { 208 | let left = currentGuideLine.getRectLeft() * scaleX; 209 | let top = currentGuideLine.getRectTop() * scaleY; 210 | let right = currentGuideLine.getRectRight() * scaleX; 211 | let bottom = currentGuideLine.getRectBottom() * scaleY; 212 | 213 | this.drawOptions(left, top, right, bottom, option, false); 214 | } 215 | }; 216 | 217 | OptionsUI.prototype.paintMultipleSelection = function(multipleSelection, option) 218 | { 219 | let scaleX = multipleSelection.main.screenshotUI.width / 640.0; 220 | let scaleY = multipleSelection.main.screenshotUI.height / 448.0; 221 | 222 | let left = multipleSelection.getRectLeft() * scaleX; 223 | let top = multipleSelection.getRectTop() * scaleY; 224 | let right = multipleSelection.getRectRight() * scaleX; 225 | let bottom = multipleSelection.getRectBottom() * scaleY; 226 | 227 | this.context.beginPath(); 228 | this.context.setLineDash([5]); 229 | this.context.rect(Math.round(left), Math.round(top), Math.round(right - left), Math.round(bottom - top)); 230 | this.context.stroke(); 231 | 232 | this.drawOptions(left, top, right, bottom, option, false); 233 | }; 234 | 235 | OptionsUI.prototype.paint = function(textDraw, option) 236 | { 237 | if(!textDraw) 238 | return; 239 | 240 | let scaleX = textDraw.main.screenshotUI.width / 640.0; 241 | let scaleY = textDraw.main.screenshotUI.height / 448.0; 242 | 243 | let left = 0.0; 244 | let top = 0.0; 245 | let right = 0.0; 246 | let bottom = 0.0; 247 | 248 | if(option == "resize-letter") 249 | { 250 | left = textDraw.getStringRectLeft() * scaleX; 251 | top = textDraw.getStringRectTop() * scaleY; 252 | right = textDraw.getStringRectRight() * scaleX; 253 | bottom = textDraw.getStringRectBottom() * scaleY; 254 | } 255 | else 256 | { 257 | left = textDraw.getRectLeft() * scaleX; 258 | top = textDraw.getRectTop() * scaleY; 259 | right = textDraw.getRectRight() * scaleX; 260 | bottom = textDraw.getRectBottom() * scaleY; 261 | } 262 | 263 | this.context.beginPath(); 264 | this.context.setLineDash([5]); 265 | this.context.rect(Math.round(left), Math.round(top), Math.round(right - left), Math.round(bottom - top)); 266 | this.context.stroke(); 267 | 268 | this.drawOptions(left, top, right, bottom, option, textDraw.font != 4 && textDraw.font != 5); 269 | }; 270 | 271 | OptionsUI.prototype.drawOptions = function(left, top, right, bottom, option, enableResizeLetter) 272 | { 273 | this.rectLeft = left; 274 | this.rectTop = top; 275 | this.rectRight = right; 276 | this.rectBottom = bottom; 277 | 278 | let x; 279 | let y; 280 | 281 | let w = enableResizeLetter ? 60 : 40; 282 | 283 | if(right > left) 284 | { 285 | x = right - (w - 4); 286 | } 287 | else 288 | { 289 | x = left - (w - 4); 290 | } 291 | 292 | if(bottom < top) 293 | { 294 | let tmp = top; 295 | top = bottom; 296 | bottom = tmp; 297 | } 298 | 299 | if(top > 24) 300 | { 301 | y = top - 24; 302 | } 303 | else 304 | { 305 | y = bottom + 8; 306 | } 307 | 308 | if(x < 4) 309 | { 310 | x = 4; 311 | } 312 | 313 | if(x > (this.width - w)) 314 | { 315 | x = this.width - w; 316 | } 317 | 318 | if(y < 4) 319 | { 320 | y = 4; 321 | } 322 | 323 | if(y > (this.height - 24)) 324 | { 325 | y = this.height - 24; 326 | } 327 | 328 | this.resizeRectLeft = x; 329 | this.resizeRectTop = y; 330 | this.resizeRectRight = x + 20; 331 | this.resizeRectBottom = y + 20; 332 | 333 | if(option == "resize") 334 | { 335 | this.context.beginPath(); 336 | this.context.setLineDash([1]); 337 | this.context.rect(x - 2, y - 2, 20, 20); 338 | this.context.stroke(); 339 | } 340 | 341 | this.context.drawImage(this.imageResizeUI.element, 0, 0, 16, 16, x, y, 16, 16); 342 | 343 | x += 20; 344 | 345 | this.moveRectLeft = x; 346 | this.moveRectTop = y; 347 | this.moveRectRight = x + 20; 348 | this.moveRectBottom = y + 20; 349 | 350 | if(option == "move") 351 | { 352 | this.context.beginPath(); 353 | this.context.setLineDash([1]); 354 | this.context.rect(x - 2, y - 2, 20, 20); 355 | this.context.stroke(); 356 | } 357 | 358 | this.context.drawImage(this.imageMoveUI.element, 0, 0, 16, 16, x, y, 16, 16); 359 | 360 | if(enableResizeLetter) 361 | { 362 | x += 20; 363 | 364 | this.resizeLetterRectLeft = x; 365 | this.resizeLetterRectTop = y; 366 | this.resizeLetterRectRight = x + 20; 367 | this.resizeLetterRectBottom = y + 20; 368 | 369 | if(option == "resize-letter") 370 | { 371 | this.context.beginPath(); 372 | this.context.setLineDash([1]); 373 | this.context.rect(x - 2, y - 2, 20, 20); 374 | this.context.stroke(); 375 | } 376 | 377 | this.context.drawImage(this.imageResizeLetterUI.element, 0, 0, 16, 16, x, y, 16, 16); 378 | } 379 | else 380 | { 381 | this.resizeLetterRectLeft = 0; 382 | this.resizeLetterRectTop = 0; 383 | this.resizeLetterRectRight = 0; 384 | this.resizeLetterRectBottom = 0; 385 | } 386 | }; 387 | 388 | OptionsUI.prototype.isInRect = function(x, y) 389 | { 390 | rectLeft = this.rectLeft; 391 | rectTop = this.rectTop; 392 | rectRight = this.rectRight; 393 | rectBottom = this.rectBottom; 394 | 395 | if(rectLeft > rectRight) 396 | { 397 | let tempRectLeft = rectLeft; 398 | rectLeft = rectRight; 399 | rectRight = tempRectLeft; 400 | } 401 | 402 | if(rectTop > rectBottom) 403 | { 404 | let tempRectTop = rectTop; 405 | rectTop = rectBottom; 406 | rectBottom = tempRectTop; 407 | } 408 | 409 | return (rectLeft - 4) < x && x < (rectRight + 4) && (rectTop - 4) < y && y < (rectBottom + 4); 410 | }; 411 | 412 | OptionsUI.prototype.isInResizeRect = function(x, y) 413 | { 414 | return this.resizeRectLeft < x && x < this.resizeRectRight && this.resizeRectTop < y && y < this.resizeRectBottom; 415 | }; 416 | 417 | OptionsUI.prototype.isInMoveRect = function(x, y) 418 | { 419 | return this.moveRectLeft < x && x < this.moveRectRight && this.moveRectTop < y && y < this.moveRectBottom; 420 | }; 421 | 422 | OptionsUI.prototype.isInResizeLetterRect = function(x, y) 423 | { 424 | return this.resizeLetterRectLeft < x && x < this.resizeLetterRectRight && this.resizeLetterRectTop < y && y < this.resizeLetterRectBottom; 425 | }; 426 | -------------------------------------------------------------------------------- /assets/js/ui/drawableui/screenshotui.js: -------------------------------------------------------------------------------- 1 | 2 | function ScreenshotUI(parent, setting) 3 | { 4 | DrawableUI.call(this, parent, setting); 5 | 6 | this.width = 0; 7 | this.height = 0; 8 | 9 | this.imageUI = new EntityUI(null, "img", {src: "./assets/images/640x480.png", onload: () => { this.resize(); this.paint(); }}); 10 | } 11 | 12 | ScreenshotUI.prototype = Object.create(DrawableUI.prototype); 13 | 14 | ScreenshotUI.prototype.resize = function() 15 | { 16 | this.width = this.imageUI.element.width; 17 | this.height = this.imageUI.element.height; 18 | 19 | if(this.width != this.element.width || this.height != this.element.height) 20 | { 21 | this.element.width = this.width; 22 | this.element.height = this.height; 23 | 24 | if(this.repaint !== undefined) 25 | this.repaint(); 26 | } 27 | }; 28 | 29 | ScreenshotUI.prototype.clear = function() 30 | { 31 | this.context.clearRect(0, 0, this.width, this.height); 32 | }; 33 | 34 | ScreenshotUI.prototype.paint = function() 35 | { 36 | this.context.drawImage(this.imageUI.element, 0, 0, this.width, this.height, 0, 0, this.width, this.height); 37 | }; 38 | 39 | ScreenshotUI.prototype.screenshotChange = function(url) 40 | { 41 | this.imageUI.element.src = url; 42 | }; 43 | -------------------------------------------------------------------------------- /assets/js/ui/drawableui/textdrawui.js: -------------------------------------------------------------------------------- 1 | 2 | function TextDrawUI(parent, setting) 3 | { 4 | DrawableUI.call(this, parent, setting); 5 | 6 | this.width = 0; 7 | this.height = 0; 8 | } 9 | 10 | TextDrawUI.prototype = Object.create(DrawableUI.prototype); 11 | 12 | TextDrawUI.prototype.resize = function(width, height) 13 | { 14 | this.width = width; 15 | this.height = height; 16 | 17 | this.element.width = width; 18 | this.element.height = height; 19 | 20 | this.element.style.width = ""; 21 | this.element.style.height = ""; 22 | }; 23 | 24 | TextDrawUI.prototype.clear = function() 25 | { 26 | this.context.clearRect(0, 0, this.width, this.height); 27 | }; 28 | 29 | TextDrawUI.prototype.paintBox = function(textDraw, detectLines) 30 | { 31 | if(!textDraw.visibility) 32 | return; 33 | 34 | let fontUI = null; 35 | let textureUI = null; 36 | 37 | if(textDraw.font == 0) 38 | { 39 | fontUI = textDraw.main.font2UI; 40 | } 41 | else if(textDraw.font == 1) 42 | { 43 | fontUI = textDraw.main.font1UI; 44 | } 45 | else if(textDraw.font == 2) 46 | { 47 | fontUI = textDraw.main.font2UI; 48 | } 49 | else if(textDraw.font == 3) 50 | { 51 | fontUI = textDraw.main.font1UI; 52 | } 53 | else if(textDraw.font == 4) 54 | { 55 | textureUI = TextureManager.instance.loadTexture(textDraw.text, textDraw.color); 56 | } 57 | 58 | if(detectLines) 59 | { 60 | if(fontUI) 61 | { 62 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, false, true); 63 | } 64 | else 65 | { 66 | textDraw.linesWidth = [0]; 67 | textDraw.linesCount = 1; 68 | 69 | textDraw.stringWidth = 0; 70 | textDraw.stringHeight = 0; 71 | } 72 | } 73 | 74 | if((textDraw.font != 4 && textDraw.font != 5 && textDraw.useBox) || (textDraw.font == 4 && !textureUI) || textDraw.font == 5) 75 | { 76 | let scaleX = textDraw.main.screenshotUI.width / 640.0; 77 | let scaleY = textDraw.main.screenshotUI.height / 448.0; 78 | 79 | let left = textDraw.getRectLeft() * scaleX - textDraw.getMargin(); 80 | let top = textDraw.getRectTop() * scaleY - textDraw.getMargin() 81 | let right = textDraw.getRectRight() * scaleX + textDraw.getMargin(); 82 | let bottom = textDraw.getStringRectBottom() * scaleY + textDraw.getMargin(); 83 | 84 | this.context.fillStyle = textDraw.getBoxColor().toRGBA(); 85 | this.context.fillRect(left, top, right - left, bottom - top); 86 | } 87 | }; 88 | 89 | TextDrawUI.prototype.paint = function(textDraw, faster, useBox) 90 | { 91 | if(!textDraw.visibility) 92 | return; 93 | 94 | let fontUI = null; 95 | let textureUI = null; 96 | 97 | if(textDraw.font == 0) 98 | { 99 | fontUI = textDraw.main.font2UI; 100 | } 101 | else if(textDraw.font == 1) 102 | { 103 | fontUI = textDraw.main.font1UI; 104 | } 105 | else if(textDraw.font == 2) 106 | { 107 | fontUI = textDraw.main.font2UI; 108 | } 109 | else if(textDraw.font == 3) 110 | { 111 | fontUI = textDraw.main.font1UI; 112 | } 113 | else if(textDraw.font == 4) 114 | { 115 | textureUI = TextureManager.instance.loadTexture(textDraw.text, textDraw.color); 116 | } 117 | 118 | let scaleX; 119 | let scaleY; 120 | 121 | if(faster) 122 | { 123 | if(this.width != 640 || this.height != 448) 124 | { 125 | this.resize(640, 448); 126 | this.element.style.width = textDraw.main.screenshotUI.width + "px"; 127 | this.element.style.height = textDraw.main.screenshotUI.height + "px"; 128 | } 129 | 130 | scaleX = 1.0; 131 | scaleY = 1.0; 132 | } 133 | else 134 | { 135 | if(fontUI) 136 | { 137 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, false, true); 138 | } 139 | else 140 | { 141 | textDraw.linesWidth = [0]; 142 | textDraw.linesCount = 1; 143 | 144 | textDraw.stringWidth = 0; 145 | textDraw.stringHeight = 0; 146 | } 147 | 148 | if(this.width != textDraw.main.screenshotUI.width || this.height != textDraw.main.screenshotUI.height) 149 | { 150 | this.resize(textDraw.main.screenshotUI.width, textDraw.main.screenshotUI.height); 151 | } 152 | 153 | scaleX = textDraw.main.screenshotUI.width / 640.0; 154 | scaleY = textDraw.main.screenshotUI.height / 448.0; 155 | } 156 | 157 | let letterSizeX = textDraw.letterSizeX * scaleX; 158 | let letterSizeY = textDraw.letterSizeY * scaleY; 159 | 160 | let x = textDraw.getRectLeft() * scaleX; 161 | let y = textDraw.getRectTop() * scaleY; 162 | 163 | if((!faster || useBox) && ((textDraw.font != 4 && textDraw.font != 5 && textDraw.useBox) || (textDraw.font == 4 && !textureUI) || textDraw.font == 5)) 164 | { 165 | let marginX = textDraw.getMargin(); 166 | let marginY = textDraw.getMargin(); 167 | 168 | if(faster) 169 | { 170 | marginX *= 640.0 / textDraw.main.screenshotUI.width; 171 | marginY *= 448.0 / textDraw.main.screenshotUI.height; 172 | } 173 | 174 | let left = textDraw.getRectLeft() * scaleX - marginX; 175 | let top = textDraw.getRectTop() * scaleY - marginY; 176 | let right = textDraw.getRectRight() * scaleX + marginX; 177 | let bottom = textDraw.getStringRectBottom() * scaleY + marginY; 178 | 179 | this.context.fillStyle = textDraw.getBoxColor().toRGBA(); 180 | this.context.fillRect(left, top, right - left, bottom - top); 181 | } 182 | 183 | if(fontUI) 184 | { 185 | if(textDraw.backgroundColor != 0x00000000) 186 | { 187 | fontUI.setColor(textDraw.backgroundColor); 188 | 189 | if(textDraw.setOutline != 0) 190 | { 191 | let setOutlineX = textDraw.setOutline * scaleX; 192 | let setOutlineY = textDraw.setOutline * scaleY; 193 | 194 | this.context.save(); 195 | this.context.translate(x - setOutlineX, y + setOutlineY); 196 | this.context.scale(letterSizeX, letterSizeY * 0.25); 197 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 198 | this.context.restore(); 199 | 200 | this.context.save(); 201 | this.context.translate(x - setOutlineX, y - setOutlineY); 202 | this.context.scale(letterSizeX, letterSizeY * 0.25); 203 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 204 | this.context.restore(); 205 | 206 | this.context.save(); 207 | this.context.translate(x + setOutlineX, y + setOutlineY); 208 | this.context.scale(letterSizeX, letterSizeY * 0.25); 209 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 210 | this.context.restore(); 211 | 212 | this.context.save(); 213 | this.context.translate(x + setOutlineX, y - setOutlineY); 214 | this.context.scale(letterSizeX, letterSizeY * 0.25); 215 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 216 | this.context.restore(); 217 | 218 | this.context.save(); 219 | this.context.translate(x + setOutlineX, y); 220 | this.context.scale(letterSizeX, letterSizeY * 0.25); 221 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 222 | this.context.restore(); 223 | 224 | this.context.save(); 225 | this.context.translate(x - setOutlineX, y); 226 | this.context.scale(letterSizeX, letterSizeY * 0.25); 227 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 228 | this.context.restore(); 229 | 230 | this.context.save(); 231 | this.context.translate(x, y + setOutlineY); 232 | this.context.scale(letterSizeX, letterSizeY * 0.25); 233 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 234 | this.context.restore(); 235 | 236 | this.context.save(); 237 | this.context.translate(x, y - setOutlineY); 238 | this.context.scale(letterSizeX, letterSizeY * 0.25); 239 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 240 | this.context.restore(); 241 | } 242 | else 243 | { 244 | let setShadowX = textDraw.setShadow * scaleX; 245 | let setShadowY = textDraw.setShadow * scaleY; 246 | 247 | this.context.save(); 248 | this.context.translate(x + setShadowX, y + setShadowY); 249 | this.context.scale(letterSizeX, letterSizeY * 0.25); 250 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, true); 251 | this.context.restore(); 252 | } 253 | } 254 | 255 | fontUI.setColor(textDraw.color); 256 | 257 | this.context.save(); 258 | this.context.translate(x, y); 259 | this.context.scale(letterSizeX, letterSizeY * 0.25); 260 | this.drawString(textDraw, fontUI, 0, 0, textDraw.text, true, false); 261 | this.context.restore(); 262 | } 263 | else if(textureUI) 264 | { 265 | let width = (textDraw.getRectRight() - textDraw.getRectLeft()) * scaleX; 266 | let height = (textDraw.getRectBottom() - textDraw.getRectTop()) * scaleY; 267 | 268 | if(width < 0) 269 | { 270 | scaleX = -1.0; 271 | 272 | x *= -1.0; 273 | width *= -1.0; 274 | } 275 | else 276 | { 277 | scaleX = 1.0; 278 | } 279 | 280 | if(height < 0) 281 | { 282 | scaleY = -1.0; 283 | 284 | y *= -1.0; 285 | height *= -1.0; 286 | } 287 | else 288 | { 289 | scaleY = 1.0; 290 | } 291 | 292 | this.context.save(); 293 | this.context.scale(scaleX, scaleY); 294 | this.context.drawImage(textureUI.element, 0, 0, textureUI.element.width, textureUI.element.height, x, y, width, height); 295 | this.context.restore(); 296 | } 297 | }; 298 | 299 | TextDrawUI.prototype.drawString = function(textDraw, fontUI, x, y, str, draw, bg) 300 | { 301 | let sign = false; 302 | 303 | let linesWidth = []; 304 | let linesCount = 1; 305 | 306 | let stringWidth = 0; 307 | let stringHeight = 0; 308 | 309 | let stringWidthMax = 0; 310 | 311 | let paddingLeft = 0; 312 | 313 | if(draw && textDraw.linesWidth.length >= 1) 314 | paddingLeft = this.getPaddingLeft(textDraw, 0); 315 | 316 | let drawed = false; 317 | 318 | for(let i = 0; i < str.length; i++) 319 | { 320 | if(sign) 321 | { 322 | if(str[i] == 'n') 323 | { 324 | if(stringWidth != 0) 325 | stringWidth -= textDraw.setOutline; 326 | 327 | if(stringWidth > stringWidthMax) 328 | stringWidthMax = stringWidth; 329 | 330 | linesWidth.push(stringWidth); 331 | linesCount++; 332 | 333 | stringWidth = x; 334 | stringHeight += 34; 335 | 336 | if(draw && textDraw.linesWidth.length >= linesCount) 337 | paddingLeft = this.getPaddingLeft(textDraw, linesCount - 1); 338 | } 339 | else if(str[i] == 'r') 340 | { 341 | if(!bg) 342 | fontUI.setColor(0xB4191DFF); 343 | } 344 | else if(str[i] == 'g') 345 | { 346 | if(!bg) 347 | fontUI.setColor(0x36682CFF); 348 | } 349 | else if(str[i] == 'b') 350 | { 351 | if(!bg) 352 | fontUI.setColor(0x323C7FFF); 353 | } 354 | else if(str[i] == 'w') 355 | { 356 | if(!bg) 357 | fontUI.setColor(0xE1E1E1FF); 358 | } 359 | else if(str[i] == 'p') 360 | { 361 | if(!bg) 362 | fontUI.setColor(0xA86EFCFF); 363 | } 364 | else if(str[i] == 'h') 365 | { 366 | if(!bg) 367 | fontUI.setColorLighter(); 368 | } 369 | else if(str[i] == '~') 370 | { 371 | sign = false; 372 | } 373 | } 374 | else 375 | { 376 | if(str[i] == '~') 377 | { 378 | sign = true; 379 | continue; 380 | } 381 | 382 | if(str[i] == ' ' && (x + (this.getStringWidth(textDraw, fontUI, str.substring(i)) + stringWidth) * textDraw.letterSizeX) > (textDraw.getRectRight() - textDraw.getRectLeft())) 383 | { 384 | if(stringWidth != 0) 385 | stringWidth -= textDraw.setOutline; 386 | 387 | if(stringWidth > stringWidthMax) 388 | stringWidthMax = stringWidth; 389 | 390 | linesWidth.push(stringWidth); 391 | linesCount++; 392 | 393 | stringWidth = 0; 394 | stringHeight += 36; 395 | 396 | if(draw && textDraw.linesWidth.length >= linesCount) 397 | paddingLeft = this.getPaddingLeft(textDraw, linesCount - 1); 398 | 399 | continue; 400 | } 401 | 402 | stringWidth += this.drawLetter(textDraw, fontUI, x + paddingLeft + stringWidth, y + stringHeight, str[i], draw); 403 | stringWidth += textDraw.setOutline; 404 | 405 | drawed = true; 406 | } 407 | } 408 | 409 | if(!draw) 410 | { 411 | if(stringWidth != 0) 412 | stringWidth -= textDraw.setOutline; 413 | 414 | if(stringWidth > stringWidthMax) 415 | stringWidthMax = stringWidth; 416 | 417 | if(drawed) 418 | { 419 | stringHeight += 36; 420 | 421 | linesWidth.push(stringWidth); 422 | } 423 | 424 | textDraw.linesWidth = linesWidth; 425 | textDraw.linesCount = linesCount; 426 | 427 | textDraw.stringWidth = stringWidthMax; 428 | textDraw.stringHeight = stringHeight; 429 | } 430 | }; 431 | 432 | TextDrawUI.prototype.drawLetter = function(textDraw, fontUI, x, y, chr, draw) 433 | { 434 | let idx = this.getLetterIndex(textDraw, chr); 435 | 436 | if(chr != ' ' && draw) 437 | this.context.drawImage(fontUI.colorUI.element, (idx % 16) * 32, Math.floor(idx / 16) * 40, 32, 40, x, y, 32, 40); 438 | 439 | return textDraw.setProportional ? fontUI.prop[idx] : fontUI.unprop; 440 | }; 441 | 442 | TextDrawUI.prototype.getStringWidth = function(textDraw, fontUI, str) 443 | { 444 | let stringWidth = 0; 445 | 446 | let sign = false; 447 | 448 | for(let i = 0; i < str.length; i++) 449 | { 450 | if(sign) 451 | { 452 | if(str[i] == 'n') 453 | break; 454 | 455 | if(str[i] == '~') 456 | { 457 | sign = false; 458 | } 459 | } 460 | else 461 | { 462 | if(str[i] == '~') 463 | { 464 | sign = true; 465 | continue; 466 | } 467 | 468 | if(str[i] == ' ' && i != 0) 469 | break; 470 | 471 | stringWidth += this.getLetterWidth(textDraw, fontUI, str[i]); 472 | stringWidth += textDraw.setOutline; 473 | } 474 | } 475 | 476 | if(stringWidth != 0) 477 | stringWidth -= textDraw.setOutline; 478 | 479 | return stringWidth; 480 | }; 481 | 482 | TextDrawUI.prototype.getLetterWidth = function(textDraw, fontUI, chr) 483 | { 484 | let idx = this.getLetterIndex(textDraw, chr); 485 | 486 | return textDraw.setProportional ? fontUI.prop[idx] : fontUI.unprop; 487 | }; 488 | 489 | TextDrawUI.prototype.getLetterIndex = function(textDraw, chr) 490 | { 491 | let idx = chr.charCodeAt(0); 492 | 493 | if(idx == 192) idx = 128; 494 | else if(idx == 193) idx = 129; 495 | else if(idx == 194) idx = 130; 496 | else if(idx == 196) idx = 131; 497 | else if(idx == 199) idx = 133; 498 | else if(idx == 200) idx = 134; 499 | else if(idx == 201) idx = 135; 500 | else if(idx == 202) idx = 136; 501 | else if(idx == 203) idx = 137; 502 | else if(idx == 204) idx = 138; 503 | else if(idx == 205) idx = 139; 504 | else if(idx == 206) idx = 140; 505 | else if(idx == 207) idx = 141; 506 | else if(idx == 210) idx = 142; 507 | else if(idx == 211) idx = 143; 508 | else if(idx == 212) idx = 144; 509 | else if(idx == 214) idx = 145; 510 | else if(idx == 217) idx = 146; 511 | else if(idx == 218) idx = 147; 512 | else if(idx == 219) idx = 148; 513 | else if(idx == 220) idx = 149; 514 | else if(idx == 224) idx = 151; 515 | else if(idx == 225) idx = 152; 516 | else if(idx == 226) idx = 153; 517 | else if(idx == 228) idx = 154; 518 | else if(idx == 231) idx = 156; 519 | else if(idx == 232) idx = 157; 520 | else if(idx == 233) idx = 158; 521 | else if(idx == 234) idx = 159; 522 | else if(idx == 235) idx = 160; 523 | else if(idx == 236) idx = 161; 524 | else if(idx == 237) idx = 162; 525 | else if(idx == 238) idx = 163; 526 | else if(idx == 239) idx = 164; 527 | else if(idx == 242) idx = 165; 528 | else if(idx == 243) idx = 166; 529 | else if(idx == 244) idx = 167; 530 | else if(idx == 246) idx = 168; 531 | else if(idx == 249) idx = 169; 532 | else if(idx == 250) idx = 170; 533 | else if(idx == 251) idx = 171; 534 | else if(idx == 252) idx = 172; 535 | else if(idx == 209) idx = 173; 536 | else if(idx == 241) idx = 174; 537 | else if(idx == 191) idx = 175; 538 | 539 | if(textDraw.font == 0 || textDraw.font == 1) 540 | { 541 | if(32 <= idx && idx <= 175) 542 | { 543 | idx -= 32; 544 | } 545 | else 546 | { 547 | idx = 10; 548 | } 549 | 550 | if(textDraw.font == 0 && idx == 6) // & 551 | idx = 10; 552 | } 553 | else 554 | { 555 | if(32 <= idx && idx <= 47) 556 | { 557 | idx -= 32; 558 | } 559 | else if(48 <= idx && idx <= 58) // 0-9 560 | { 561 | idx += 96; 562 | } 563 | else if(59 <= idx && idx <= 64) 564 | { 565 | idx -= 32; 566 | } 567 | else if(65 <= idx && idx <= 90) // A-Z 568 | { 569 | idx += 90; 570 | } 571 | else if(91 <= idx && idx <= 96) 572 | { 573 | idx -= 32; 574 | } 575 | else if(97 <= idx && idx <= 122) // a-z 576 | { 577 | idx += 58; 578 | } 579 | else if(123 <= idx && idx <= 150) 580 | { 581 | idx -= 32; 582 | } 583 | else if(151 <= idx && idx <= 175) 584 | { 585 | idx += 30; 586 | } 587 | else 588 | { 589 | idx = 10; 590 | } 591 | 592 | if(textDraw.font == 2 && idx == 6) // & 593 | idx = 10; 594 | } 595 | 596 | return idx; 597 | }; 598 | 599 | TextDrawUI.prototype.getPaddingLeft = function(textDraw, lineNumber) 600 | { 601 | let paddingLeft = 0; 602 | 603 | switch(textDraw.alignment) 604 | { 605 | case 2: 606 | paddingLeft += textDraw.textSizeY / 2 / textDraw.letterSizeX; 607 | paddingLeft -= textDraw.linesWidth[lineNumber] / 2; 608 | paddingLeft -= textDraw.letterSizeX / 2; 609 | break; 610 | 611 | case 3: 612 | paddingLeft += (textDraw.getRectRight() - textDraw.getRectLeft()) / textDraw.letterSizeX; 613 | paddingLeft -= textDraw.linesWidth[lineNumber]; 614 | paddingLeft -= textDraw.letterSizeX; 615 | break; 616 | } 617 | 618 | return paddingLeft; 619 | } -------------------------------------------------------------------------------- /assets/js/ui/entityui.js: -------------------------------------------------------------------------------- 1 | 2 | function EntityUI(parent, tagName, setting) 3 | { 4 | this.element = document.createElement(tagName); 5 | 6 | for(key in setting) 7 | { 8 | if(key == "class") 9 | { 10 | if(typeof setting.class === "string") 11 | { 12 | this.element.classList.add(setting.class); 13 | } 14 | else 15 | { 16 | for(cls in setting.class) 17 | { 18 | this.element.classList.add(setting.class[cls]); 19 | } 20 | } 21 | 22 | continue; 23 | } 24 | 25 | if(key == "style") 26 | { 27 | for(sty in setting.style) 28 | { 29 | this.element.style[sty] = setting.style[sty]; 30 | } 31 | 32 | continue; 33 | } 34 | 35 | if(key == "keydown" || key == "keyup" || key == "mousedown" || key == "mouseup" || key == "mousemove" || key == "click" || key == "contextmenu" || key == "focusin" || key == "focusout" || key == "change") 36 | { 37 | this.element.addEventListener(key, setting[key]); 38 | continue; 39 | } 40 | 41 | this.element[key] = setting[key]; 42 | } 43 | 44 | if(parent) 45 | { 46 | if(parent instanceof EntityUI) 47 | { 48 | parent.element.appendChild(this.element); 49 | } 50 | else if(parent instanceof HTMLElement) 51 | { 52 | parent.appendChild(this.element); 53 | } 54 | else if(typeof parent === "string") 55 | { 56 | document.querySelector(parent).appendChild(this.element); 57 | } 58 | } 59 | 60 | Object.defineProperty(this.element, "entityUI", {value: this, writable: false}); 61 | } 62 | 63 | EntityUI.prototype.appendSpacing = function() 64 | { 65 | return new EntityUI(this, "div", {class: "spacing"}); 66 | }; 67 | 68 | EntityUI.prototype.appendLineBreak = function() 69 | { 70 | return new EntityUI(this, "br", {}); 71 | }; 72 | 73 | EntityUI.prototype.appendStaticLine = function() 74 | { 75 | return new EntityUI(this, "hr", {}); 76 | }; 77 | 78 | EntityUI.prototype.appendStaticText = function(text) 79 | { 80 | return new EntityUI(this, "span", {innerText: text}); 81 | }; 82 | 83 | EntityUI.prototype.remove = function() 84 | { 85 | if(this.element.parentNode) 86 | this.element.parentNode.removeChild(this.element); 87 | }; 88 | 89 | EntityUI.prototype.isInBoundingClientRect = function(x, y) 90 | { 91 | let rect = this.element.getBoundingClientRect(); 92 | 93 | return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom; 94 | }; 95 | 96 | EntityUI.prototype.hasScrollBar = function() 97 | { 98 | return this.element.scrollHeight > this.element.clientHeight; 99 | }; 100 | -------------------------------------------------------------------------------- /assets/js/ui/fileboxui.js: -------------------------------------------------------------------------------- 1 | 2 | function FileBoxUI(parent, setting) 3 | { 4 | EntityUI.call(this, parent, "input", setting); 5 | 6 | if(setting.type === undefined) 7 | this.element.type = "file"; 8 | } 9 | 10 | FileBoxUI.prototype = Object.create(EntityUI.prototype); 11 | -------------------------------------------------------------------------------- /assets/js/ui/listboxui.js: -------------------------------------------------------------------------------- 1 | 2 | function ListBoxUI(parent, setting) 3 | { 4 | EntityUI.call(this, parent, "select", setting); 5 | } 6 | 7 | ListBoxUI.prototype = Object.create(EntityUI.prototype); 8 | 9 | ListBoxUI.prototype.appendOption = function(text) 10 | { 11 | return new EntityUI(this, "option", {innerText: text}); 12 | }; 13 | -------------------------------------------------------------------------------- /assets/js/ui/resizerui.js: -------------------------------------------------------------------------------- 1 | 2 | function ResizerUI(parent, minY) 3 | { 4 | EntityUI.call(this, parent, "div", {class: "resizer", mousedown: (e) => { this.startResizing(e); }}); 5 | 6 | this.resizing = false; 7 | this.resizingY = 0; 8 | 9 | this.minY = minY; 10 | 11 | this.appendStaticLine(); 12 | } 13 | 14 | ResizerUI.prototype = Object.create(EntityUI.prototype); 15 | 16 | ResizerUI.prototype.startResizing = function(e) 17 | { 18 | main.overrideCursor(true); 19 | 20 | document.body.style.cursor = "row-resize"; 21 | document.body.style.userSelect = "none"; 22 | 23 | this.resizing = true; 24 | this.resizingY = (this.element.getBoundingClientRect().top - this.element.previousSibling.getBoundingClientRect().height) + this.element.getBoundingClientRect().height / 2; 25 | }; 26 | 27 | ResizerUI.prototype.stopResizing = function(e) 28 | { 29 | main.overrideCursor(false); 30 | 31 | document.body.style.cursor = ""; 32 | document.body.style.userSelect = ""; 33 | 34 | this.resizing = false; 35 | this.resizingY = 0; 36 | }; 37 | 38 | ResizerUI.prototype.resize = function(y) 39 | { 40 | if(y < this.minY) 41 | { 42 | y = this.minY; 43 | } 44 | 45 | this.element.previousSibling.style.height = y + "px"; 46 | }; 47 | -------------------------------------------------------------------------------- /assets/js/ui/textboxui.js: -------------------------------------------------------------------------------- 1 | 2 | function TextBoxUI(parent, setting) 3 | { 4 | EntityUI.call(this, parent, "input", setting); 5 | 6 | if(setting.type === undefined) 7 | this.element.type = "text"; 8 | } 9 | 10 | TextBoxUI.prototype = Object.create(EntityUI.prototype); 11 | -------------------------------------------------------------------------------- /assets/js/util.js: -------------------------------------------------------------------------------- 1 | 2 | String.prototype.padZero = function(len) 3 | { 4 | let pad = ""; 5 | 6 | while((pad.length + this.length) < len) 7 | pad += "0"; 8 | 9 | return pad + this; 10 | }; 11 | 12 | Number.prototype.toPlainString = function() 13 | { 14 | let num = this.valueOf(); 15 | let str = this.toString(); 16 | 17 | if(Math.abs(num) < 1.0) 18 | { 19 | let e = parseInt(num.toString().split("e-")[1]); 20 | 21 | if(e) 22 | { 23 | let negative = num < 0; 24 | 25 | if(negative) 26 | num *= -1; 27 | 28 | num *= Math.pow(10, e - 1); 29 | str = '0.' + (new Array(e)).join("0") + num.toString().substring(2); 30 | 31 | if(negative) 32 | str = "-" + str; 33 | } 34 | } 35 | else 36 | { 37 | let e = parseInt(num.toString().split("+")[1]); 38 | 39 | if(e > 20) 40 | { 41 | e -= 20; 42 | num /= Math.pow(10, e); 43 | str = num.toString() + (new Array(e + 1)).join("0"); 44 | } 45 | } 46 | 47 | if(str.indexOf(".") != -1) 48 | { 49 | str = str.split("."); 50 | 51 | if(str[1].length > 6) 52 | str[1] = str[1].substring(0, 6); 53 | 54 | while(str[1].length != 0) 55 | { 56 | if(str[1].slice(-1) != "0") 57 | break; 58 | 59 | str[1] = str[1].slice(0, -1); 60 | } 61 | 62 | if(str[1].length == 0) 63 | str.pop(); 64 | 65 | str = str.join("."); 66 | } 67 | 68 | return str; 69 | }; 70 | 71 | Number.prototype.toRGBA = function() 72 | { 73 | let color = this.valueOf(); 74 | 75 | let red = (color >> 24) & 0xFF; 76 | let green = (color >> 16) & 0xFF; 77 | let blue = (color >> 8) & 0xFF; 78 | let alpha = (color & 0xFF) / 0xFF; 79 | 80 | return "rgba(" + red + ", " + green + ", " + blue + ", " + alpha + ")"; 81 | }; 82 | 83 | Number.prototype.toRGB = function() 84 | { 85 | let color = this.valueOf(); 86 | 87 | let red = (color >> 24) & 0xFF; 88 | let green = (color >> 16) & 0xFF; 89 | let blue = (color >> 8) & 0xFF; 90 | 91 | return "rgb(" + red + ", " + green + ", " + blue + ")"; 92 | }; 93 | 94 | Number.prototype.getRGB = function() 95 | { 96 | let color = this.valueOf(); 97 | return (color >> 8) & 0xFFFFFF; 98 | }; 99 | 100 | Number.prototype.getAlpha = function() 101 | { 102 | let color = this.valueOf(); 103 | return (color & 0xFF) / 0xFF; 104 | }; 105 | 106 | Number.prototype.getPercentOf = function(min, max) 107 | { 108 | let val = this.valueOf(); 109 | 110 | let total = max - min; 111 | let value = val - min; 112 | 113 | if(total == 0) 114 | return 0; 115 | 116 | return value * 100 / total; 117 | }; 118 | -------------------------------------------------------------------------------- /assets/style/main.css: -------------------------------------------------------------------------------- 1 | 2 | html, body 3 | { 4 | height: 100%; 5 | margin: 0px; 6 | padding: 0px; 7 | overflow: hidden; 8 | } 9 | 10 | span 11 | { 12 | margin: 2px 5px; 13 | font-family: verdana; 14 | font-size: 12px; 15 | color: #ffffff; 16 | } 17 | 18 | hr 19 | { 20 | border-top: 1px solid #262626; 21 | border-bottom: 1px solid #808080; 22 | } 23 | 24 | button, select, input, textarea 25 | { 26 | width: 240px; 27 | padding: 2px; 28 | margin: 2px 5px; 29 | font-family: verdana; 30 | font-size: 12px; 31 | font-weight: bold; 32 | color: #ffffff; 33 | background-color: #3a3a3a; 34 | border: 1px solid #292929; 35 | box-sizing: border-box; 36 | } 37 | 38 | button 39 | { 40 | background-image: linear-gradient(#757575, #6c6c6c, #626262); 41 | border-radius: 5px; 42 | cursor: pointer; 43 | } 44 | 45 | button:hover 46 | { 47 | background-image: linear-gradient(#3f3f3f, #3c3c3c, #373737); 48 | } 49 | 50 | .colorPicker 51 | { 52 | display: inline-block; 53 | position: relative; 54 | margin: 2px 5px; 55 | } 56 | 57 | input.textBoxLeft 58 | { 59 | width: 118px; 60 | margin-right: 0px; 61 | } 62 | 63 | input.textBoxRight 64 | { 65 | width: 118px; 66 | margin-left: 4px; 67 | } 68 | 69 | input.textBoxColor 70 | { 71 | width: 219px; 72 | margin: 0px; 73 | border-right: 0px; 74 | } 75 | 76 | input.textBoxColor:focus + * 77 | { 78 | outline: none !important; 79 | border: 1px solid #919191; 80 | border-left: 0px; 81 | box-shadow: 0 0 2px #919191; 82 | } 83 | 84 | input[type=color] 85 | { 86 | position: absolute; 87 | width: 21px; 88 | height: 100%; 89 | padding: 5px; 90 | margin: 0px; 91 | background-image: linear-gradient(#757575, #6c6c6c, #626262); 92 | border-left: 0px; 93 | border-radius: 0px 5px 5px 0px; 94 | cursor: pointer; 95 | } 96 | 97 | input[type=checkbox] 98 | { 99 | width: 14px; 100 | margin-right: 0px; 101 | } 102 | 103 | textarea 104 | { 105 | width: 480px; 106 | height: 100px; 107 | } 108 | 109 | input:focus, textarea:focus 110 | { 111 | outline: none !important; 112 | border: 1px solid #919191; 113 | box-shadow: 0 0 2px #919191; 114 | } 115 | 116 | canvas 117 | { 118 | display: block; 119 | position: absolute; 120 | } 121 | 122 | #main 123 | { 124 | display: table; 125 | width: 100%; 126 | height: 100%; 127 | } 128 | 129 | #tabs 130 | { 131 | display: table-cell; 132 | position: relative; 133 | width: 76px; 134 | background-color: #535353; 135 | border-left: 1px solid #262626; 136 | border-right: 1px solid #808080; 137 | } 138 | 139 | #tabs .addProjectTab 140 | { 141 | width: 64px; 142 | height: 64px; 143 | margin: 5px; 144 | background-image: url(../images/add.png); 145 | background-repeat: no-repeat; 146 | background-size: 56px 56px; 147 | background-position: center center; 148 | border: 1px solid #535353; 149 | cursor: pointer; 150 | } 151 | 152 | #tabs .addProjectTab:hover 153 | { 154 | background-color: #3a3a3a; 155 | border: 1px solid #292929; 156 | } 157 | 158 | #tabs .projectTab 159 | { 160 | width: 64px; 161 | height: 64px; 162 | margin: 0px 5px 5px 5px; 163 | background-color: #3a3a3a; 164 | border: 1px solid #292929; 165 | cursor: pointer; 166 | } 167 | 168 | #tabs .projectTab:hover 169 | { 170 | border: 1px solid #6d6d6d; 171 | box-shadow: 0 0 2px #6d6d6d; 172 | } 173 | 174 | #tabs .currentProjectTab 175 | { 176 | background-color: #3a3a3a; 177 | border: 1px solid #808080; 178 | box-shadow: 0 0 2px #808080; 179 | } 180 | 181 | #controls 182 | { 183 | display: table-cell; 184 | position: relative; 185 | width: 250px; 186 | background-color: #535353; 187 | border-left: 1px solid #262626; 188 | border-right: 1px solid #808080; 189 | } 190 | 191 | #screen 192 | { 193 | display: table-cell; 194 | position: relative; 195 | background-color: #262626; 196 | border-left: 1px solid #262626; 197 | border-right: 1px solid #808080; 198 | } 199 | 200 | .textDrawList 201 | { 202 | width: 240px; 203 | height: 126px; 204 | margin: 2px 5px; 205 | background-color: #3a3a3a; 206 | border: 1px solid #292929; 207 | box-sizing: border-box; 208 | overflow-x: hidden; 209 | overflow-y: scroll; 210 | } 211 | 212 | .textDrawItem 213 | { 214 | position: relative; 215 | width: 100%; 216 | height: 25px; 217 | border-bottom: 1px solid #292929; 218 | box-sizing: border-box; 219 | cursor: pointer; 220 | user-select: none; 221 | } 222 | 223 | .textDrawItem:hover 224 | { 225 | background-color: #6d6d6d; 226 | } 227 | 228 | .textDrawItem canvas, .textDrawItem img 229 | { 230 | display: block; 231 | position: absolute; 232 | height: 24px; 233 | border-right: 1px solid #292929; 234 | cursor: move; 235 | user-select: none; 236 | } 237 | 238 | .textDrawItem span 239 | { 240 | margin-left: 32px; 241 | white-space: nowrap; 242 | } 243 | 244 | .textDrawItem span:first-child 245 | { 246 | margin-left: 2px; 247 | } 248 | 249 | .currentTextDrawItem, .currentTextDrawItem:hover 250 | { 251 | background-color: #808080; 252 | } 253 | 254 | .lastTextDrawItem 255 | { 256 | border-bottom: none; 257 | } 258 | 259 | .textDrawItem .visibility 260 | { 261 | display: inline-block; 262 | position: absolute; 263 | right: 0px; 264 | width: 24px; 265 | height: 24px; 266 | background-color: #3a3a3a; 267 | background-image: url(../images/visibility.png); 268 | background-repeat: no-repeat; 269 | background-position: 0px 0px; 270 | user-select: none; 271 | } 272 | 273 | .textDrawItem .visibility:hover 274 | { 275 | background-position-x: -24px; 276 | } 277 | 278 | .textDrawItem:hover .visibility 279 | { 280 | background-color: #6d6d6d; 281 | } 282 | 283 | .currentTextDrawItem .visibility, .currentTextDrawItem:hover .visibility 284 | { 285 | background-color: #808080; 286 | } 287 | 288 | .textureList 289 | { 290 | width: 440px; 291 | height: 140px; 292 | overflow-y: scroll; 293 | overflow-x: hidden; 294 | } 295 | 296 | .textureItem 297 | { 298 | display: inline-block; 299 | margin: 2px; 300 | background-color: #3a3a3a; 301 | border: 1px solid #292929; 302 | font-size: 0px; 303 | } 304 | 305 | .textureItem:hover 306 | { 307 | background-color: #6d6d6d; 308 | } 309 | 310 | .resizer 311 | { 312 | padding: 6px 0px; 313 | cursor: row-resize; 314 | } 315 | 316 | .resizer hr 317 | { 318 | margin: 0px; 319 | } 320 | 321 | .overrideCursor 322 | { 323 | position: absolute; 324 | left: 0px; 325 | top: 0px; 326 | width: 100vw; 327 | height: 100vh; 328 | z-index: 99999; 329 | } 330 | 331 | .contextMenu 332 | { 333 | position: absolute; 334 | min-width: 120px; 335 | background-color: #F0F0F0; 336 | border: 1px solid #A0A0A0; 337 | z-index: 999; 338 | user-select: none; 339 | } 340 | 341 | .contextMenu .contextItem 342 | { 343 | position: relative; 344 | margin: 2px; 345 | padding: 5px 20px; 346 | background-repeat: no-repeat; 347 | background-size: 16px; 348 | background-position: 2px 3px; 349 | font-family: arial; 350 | font-size: 10px; 351 | color: #000000; 352 | white-space: nowrap; 353 | cursor: pointer; 354 | } 355 | 356 | .contextMenu .contextItem:hover 357 | { 358 | background-color: #3399FF; 359 | } 360 | 361 | .contextMenu .contextItemDisabled 362 | { 363 | color: #6d6d6d; 364 | } 365 | 366 | .contextMenu .contextItemDisabled:hover 367 | { 368 | background-color: #F0F0F0; 369 | } 370 | 371 | .contextMenu .contextItem .contextMenu 372 | { 373 | display: none; 374 | } 375 | 376 | .contextMenu .contextItem:hover .contextMenu 377 | { 378 | display: block; 379 | } 380 | 381 | .contextMenu hr 382 | { 383 | margin: 0px; 384 | border-left: 0px; 385 | border-right: 0px; 386 | border-top: 1px solid #A0A0A0; 387 | border-bottom: 1px solid #FFFFFF; 388 | } 389 | 390 | .dialog 391 | { 392 | display: flex; 393 | flex-direction: column; 394 | position: absolute; 395 | left: 50%; 396 | top: 50%; 397 | transform: translate(-50%, -50%); 398 | background-color: #535353; 399 | border: 1px solid #282828; 400 | border-radius: 5px; 401 | resize: both; 402 | overflow: hidden; 403 | } 404 | 405 | .dialog .dialogTitleBar 406 | { 407 | height: 21px; 408 | line-height: 21px; 409 | font-family: verdana; 410 | font-size: 10px; 411 | font-weight: bold; 412 | text-align: center; 413 | color: #ffffff; 414 | background-image: linear-gradient(#393939, #353535, #323232); 415 | border-top: 1px solid #474747; 416 | border-bottom: 1px solid #282828; 417 | cursor: move; 418 | user-select: none; 419 | } 420 | 421 | .dialog .dialogContent 422 | { 423 | flex-direction: column; 424 | flex: 1 1 auto; 425 | padding: 5px; 426 | padding-bottom: 0px; 427 | border-top: #6a6a6a solid 1px; 428 | } 429 | 430 | .dialog .dialogButtons 431 | { 432 | padding: 5px; 433 | padding-top: 0px; 434 | text-align: center; 435 | } 436 | 437 | .dialog .dialogButtons button 438 | { 439 | width: 100px; 440 | } 441 | 442 | .dialog .dialogContent input, .dialog .dialogContent select, .dialog .dialogContent hr 443 | { 444 | width: calc(100% - 10px); 445 | } 446 | 447 | .dialog .dialogContent input[type=checkbox] 448 | { 449 | width: 14px; 450 | } 451 | 452 | .dialog .dialogContent input.textBoxLeft 453 | { 454 | width: calc(50% - 7px); 455 | } 456 | 457 | .dialog .dialogContent input.textBoxRight 458 | { 459 | width: calc(50% - 7px); 460 | } 461 | 462 | .dialog .dialogContent textarea, .dialog .dialogContent .textDrawList, .dialog .dialogContent .textureList 463 | { 464 | flex: 1 1 auto; 465 | width: calc(100% - 10px); 466 | resize: none; 467 | } 468 | 469 | .scrollable 470 | { 471 | position: absolute; 472 | left: 0; 473 | top: 0; 474 | right: 0; 475 | bottom: 0; 476 | white-space: nowrap; 477 | overflow-y: auto; 478 | } 479 | 480 | .scrollable.scrollbarThin 481 | { 482 | scrollbar-width: thin; 483 | } 484 | 485 | .resizable 486 | { 487 | resize: both; 488 | } 489 | 490 | .spacing 491 | { 492 | height: 4px; 493 | } 494 | 495 | .rightPointing 496 | { 497 | position: absolute; 498 | right: 3px; 499 | top: 50%; 500 | transform: translate(0px,-50%); 501 | } 502 | 503 | .rightPointing:after 504 | { 505 | content: "\25BA"; 506 | } 507 | 508 | .scrollable.scrollbarThin::-webkit-scrollbar 509 | { 510 | width: 8px; 511 | height: 8px; 512 | background-color: #404040; 513 | } 514 | 515 | .scrollable.scrollbarThin::-webkit-scrollbar-corner 516 | { 517 | background-color: #404040; 518 | } 519 | 520 | .scrollable.scrollbarThin::-webkit-scrollbar-thumb 521 | { 522 | background: #8a8a8a; 523 | border: 1px solid #404040; 524 | } 525 | 526 | ::-webkit-scrollbar 527 | { 528 | width: 15px; 529 | height: 15px; 530 | background-color: #212121; 531 | } 532 | 533 | ::-webkit-scrollbar-corner 534 | { 535 | background-color: #212121; 536 | } 537 | 538 | ::-webkit-scrollbar-thumb 539 | { 540 | background: #787878; 541 | border: 1px solid #212121; 542 | } 543 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TextDraw Editor 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | --------------------------------------------------------------------------------