diff options
author | bai | 2019-03-29 02:14:43 +0000 |
---|---|---|
committer | bai | 2019-03-29 02:14:43 +0000 |
commit | 95dfe14528663923ca2a88ec928f1d8d9df2402b (patch) | |
tree | 5bc88d1466957f1aa39043b056bde5c439648022 /static/js/paintbbs | |
download | weabot-95dfe14528663923ca2a88ec928f1d8d9df2402b.tar.gz weabot-95dfe14528663923ca2a88ec928f1d8d9df2402b.tar.xz weabot-95dfe14528663923ca2a88ec928f1d8d9df2402b.zip |
Init
Diffstat (limited to 'static/js/paintbbs')
-rw-r--r-- | static/js/paintbbs/PaintBBS-1.1.11.css | 535 | ||||
-rw-r--r-- | static/js/paintbbs/PaintBBS-1.1.11.js | 5686 | ||||
-rw-r--r-- | static/js/paintbbs/PaintBBS-1.3.4.css | 547 | ||||
-rw-r--r-- | static/js/paintbbs/PaintBBS-1.3.4.js | 6171 |
4 files changed, 12939 insertions, 0 deletions
diff --git a/static/js/paintbbs/PaintBBS-1.1.11.css b/static/js/paintbbs/PaintBBS-1.1.11.css new file mode 100644 index 0000000..776f63d --- /dev/null +++ b/static/js/paintbbs/PaintBBS-1.1.11.css @@ -0,0 +1,535 @@ +.NEO { + margin:0; + line-height:18px; + + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + + touch-callout: none; + -webkit-touch-callout: none; +} + +.NEO *:active, +.NEO *:hover { + cursor: default; +} + +.NEO #container{ + width: 100%; + height: 100%; + position: relative; + border: 1px dotted transparent; +} + +.NEO #center{ + display: table; + position: relative; + height: 100%; + margin: auto; +} + +.NEO #toolsWrapper{ + width: 52px; + display: table; + position:absolute; + top: 0; + right: -3px; +} + +.NEO #tools{ + width: 52px; + display: table-cell; + vertical-align: middle; + position: relative; +} + +.NEO #painterContainer{ + display:table-cell; + vertical-align: middle; + position: relative; +} + +.NEO #painterWrapper{ + padding: 0 55px 0 0; + position: relative; + + float:right; /* なぜかChrome55でずれるので対策 */ +} + +.NEO #upper { + height:30px; + padding-right: 20px; + text-align:right; +} + +.NEO #lower { + height:30px; +} + +.NEO #painter { + position: relative; + padding: 20px 20px 20px 20px; +} + +.NEO #canvas { + position: relative; + width: 300px; + height: 300px; + background-color: white; +} + +.NEO #headerButtons { + position: absolute; + top: 5px; + left: 5px; +} + +.NEO #footerButtons { + position: absolute; + bottom: 5px; + left: 5px; +} + + +/* +----------------------- + Modal Window +----------------------- +*/ + +.NEO #pageView{ + background-color: white; +} + +.NEO #windowView{ + z-index: 9999; + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: white; +} + +/* +----------------------- + Controls +----------------------- +*/ + +.NEO #zoomMinus { + padding: 0; + margin: 0; + width:16px; + height:16px; + margin-left:1px; +} + +.NEO #zoomPlus { + padding: 0; + margin: 0; + width:16px; + height:16px; +} + +.NEO #zoomMinusWrapper { + position: absolute; + right: -20px; + bottom: -21px; + width: 19px; + height: 19px; + text-align:center; +} + +.NEO #zoomPlusWrapper { + position: absolute; + left: -21px; + bottom: -21px; + width: 19px; + height: 19px; + text-overflow: hidden; + text-align:center; +} + +.NEO #scrollH { + position: absolute; + left: 1px; + bottom: -20px; + width: calc(100% - 2px); + height: 18px; +} + +.NEO #scrollV { + position: absolute; + right: -20px; + top: 1px; + width: 18px; + height: calc(100% - 2px); +} + +.NEO #scrollH div { + position: absolute; + width: 50px; + height: 16px; +} + +.NEO #scrollV div { + position: absolute; + width: 16px; + height: 50px; +} + +.NEO #scrollH div:hover {} +.NEO #scrollV div:hover {} + +.NEO #neoWarning { + position: absolute; + left: 5px; + top: 5px; + color: red; + pointer-events: none; + text-align: left; + transition: all 2s; +} + +/* +----------------------- + Widgets +----------------------- +*/ + +.NEO .buttonOff { + display: inline-block; + border: 1px solid white; + height: 19px; + padding: 3px; + height: 16px; + font-size: 15px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + margin-right: 4px; + + border-left: 1px solid rgba(0, 0, 0, 0); + border-top: 1px solid rgba(0, 0, 0, 0); + border-right: 1px solid rgba(0, 0, 0, 0); + border-bottom: 1px solid rgba(0, 0, 0, 0); + + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + margin: 1px; + +} + +.NEO .buttonOff:hover {} + +.NEO .buttonOff:active, +.NEO .buttonOn { + display: inline-block; + height: 19px; + padding: 3px; + height: 16px; + font-size: 15px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + margin-right: 4px; + + border-right: 1px solid rgba(0, 0, 0, 0); + border-bottom: 1px solid rgba(0, 0, 0, 0); + + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + margin: 1px; +} + +.NEO .toolTipOff, +.NEO .toolTipFixed { + position:relative; + padding: 0; + margin: 0; + margin-top: 3px; + margin-bottom: 3px; + + width: 46px; + height: 18px; + border-top: 1px solid #ffffff; + border-left: 1px solid #ffffff; + border-right: 1px solid #9397b2; + border-bottom: 1px solid #9397b2; +} + +.NEO .toolTipOn { + position:relative; + padding: 0; + margin: 0; + margin-top: 3px; + margin-bottom: 3px; + + width: 46px; + height: 18px; + border-top: 1px solid rgba(0, 0, 0, 0); + border-left: 1px solid rgba(0, 0, 0, 0); + border-right: 1px solid #ffffff; + border-bottom: 1px solid #ffffff; +} + +.NEO .toolTipOff canvas, +.NEO .toolTipOn canvas, +.NEO .toolTipFixed canvas { + position: absolute; + top: 0; + left: 0; +} + +.NEO .toolTipOff .label, +.NEO .toolTipOn .label, +.NEO .toolTipFixed .label { + position: absolute; + bottom: -4px; + left: 1px; + font-size:12px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: -1px; +} + +.NEO .colorTips { + position:relative; + width: 48px; + height: 144px; + padding: 0; + margin: 0; + margin-top: 4px; + margin-left: 0px; +} + +.NEO .colorTipOff { + position: absolute; + overflow: hidden; + width: 22px; + height: 18px; + margin: -1px 4px 0px 0px; + padding: 0; +} + +.NEO .colorTipOff img { + left: 0; + opacity: 0.5; + position: absolute; + pointer-events:none; +} + +.NEO .colorTipOn { + position: absolute; + overflow: hidden; + width: 22px; + height: 18px; + margin: -1px 4px 0px 0px; + padding: 0; +} + +.NEO .colorTipOn img { + left: -22px; + opacity: 0.5; + position: absolute; + pointer-events:none; +} + +.NEO .colorSlider { + width: 48px; + height:13px; + position: relative; + margin-top: 3px; +} + +.NEO .colorSlider .label { + pointer-events: none; + position: absolute; + left: 2px; + bottom: -3px; + font-size:12px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: middle; +} + +.NEO .colorSlider .slider { + position: absolute; + height: 100%; + left: 0px; + width: 50%; + background-color: #fa9696; + box-shadow: -1px 0 0 0px rgba(0, 0, 0, 0.3) inset; +} + +.NEO .colorSlider .hit { + position:absolute; + width: 60px; + height: 13px; + left: -6px; + background-color: white; + opacity: 0.01; +} + +.NEO .sizeSlider { + width: 48px; + height:33px; + position: relative; + margin-top: 4px; +} + +.NEO .sizeSlider .label { + pointer-events: none; + position: absolute; + left: 2px; + bottom: -3px; + font-size:12px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: middle; +} + +.NEO .sizeSlider .slider { + position: absolute; + width: 100%; + top: 0px; + height: 33%; + background-color: #82f238; + box-shadow: 0 -1px 0 0px rgba(0, 0, 0, 0.3) inset; +} + +.NEO .sizeSlider .hit { + position:absolute; + width: 48px; + height: 41px; + top: -4px; + background-color: white; + opacity: 0.01; +} + +.NEO .reserveControl { + width: 48px; + height: 13px; + position: relative; +} + +.NEO .reserveControl .reserve { + position: absolute; + width: 11px; + height: 8px; + background-color: white; +} + +.NEO .layerControl { + width: 48px; + height: 20px; + position: relative; + margin-top: 6px; +} + +.NEO .layerControl .bg { + position: absolute; + width: 44px; + height: 9px; + margin: 0; + + top: 0px; + left: 2px; +} + +.NEO .layerControl .line1 { + position: absolute; + width: 50px; + height:10px; + margin: 0; + padding: 0; + + top: 0px; + left: -1px; + background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent); +} + +.NEO .layerControl .line0 { + position: absolute; + width: 50px; + height: 10px; + margin: 0; + padding: 0; + + top: 10px; + left: -1px; + background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent); +} + +.NEO .layerControl .label1 { + position: absolute; + left: 2px; + Top: -4px; + font-size:11px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: baseline; +} + +.NEO .layerControl .label0 { + position: absolute; + left: 2px; + Top: 6px; + font-size:11px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: baseline; +} + +/* +----------------------- + InputText +----------------------- +*/ + +.NEO .inputText { + z-index: 100000; + position: absolute; + + text-align: left; + white-space: nowrap; + color: #0000ff; + + font-family: 'Arial'; + padding: 1px 5px 1px 5px; + font-size: 32px; + + line-height: 40px; + height: 40px; + min-width: 10em; + + bottom: 0px; + left: 250px; + + border: 1px solid #aaa; + background-color: white; +} + +*[contenteditable] { + user-select: auto !important; + -webkit-user-select: auto !important; + -moz-user-select: auto !important; +} + +#testtext { + user-select: auto !important; + -webkit-user-select: auto !important; + -moz-user-select: auto; +} + +[contenteditable="true"]:focus { + outline: 1px solid #b1d6fd; + border: 1px solid #b1d6fd; +} diff --git a/static/js/paintbbs/PaintBBS-1.1.11.js b/static/js/paintbbs/PaintBBS-1.1.11.js new file mode 100644 index 0000000..8ca50e7 --- /dev/null +++ b/static/js/paintbbs/PaintBBS-1.1.11.js @@ -0,0 +1,5686 @@ +'use strict'; + +document.addEventListener("DOMContentLoaded", function() { + Neo.init(); + + if (!navigator.userAgent.match("Electron")) { + Neo.start(); + } +}); + + +var Neo = function() {}; + +Neo.version = "1.1.11"; +Neo.painter; +Neo.fullScreen = false; +Neo.uploaded = false; + +Neo.config = { + width: 300, + height: 300, + + color_bk: "#ccccff", + color_bk2: "#bbbbff", + color_tool_icon: "#e8dfae", + color_icon: "#ccccff", + color_iconselect: "#ffaaaa", + color_text: "#666699", + color_bar: "#6f6fae", + + tool_color_button: "#e8dfae", + tool_color_button2: "#f8daaa", + tool_color_text: "#773333", + tool_color_bar: "#ddddff", + tool_color_frame: "#000000", + + colors: [ + "#000000", "#FFFFFF", + "#B47575", "#888888", + "#FA9696", "#C096C0", + "#FFB6FF", "#8080FF", + "#25C7C9", "#E7E58D", + "#E7962D", "#99CB7B", + "#FCECE2", "#F9DDCF" + ] +}; + +Neo.reservePen = {}; +Neo.reserveEraser = {}; + +Neo.SLIDERTYPE_RED = 0; +Neo.SLIDERTYPE_GREEN = 1; +Neo.SLIDERTYPE_BLUE = 2; +Neo.SLIDERTYPE_ALPHA = 3; +Neo.SLIDERTYPE_SIZE = 4; + +document.neo = Neo; + +Neo.init = function() { + var applets = document.getElementsByTagName('applet'); + if (applets.length == 0) { + applets = document.getElementsByTagName('applet-dummy'); + } + + for (var i = 0; i < applets.length; i++) { + var applet = applets[i]; + var name = applet.attributes.name.value; + if (name == "paintbbs") { + Neo.applet = applet; + Neo.createContainer(applet); + Neo.initConfig(applet); + Neo.init2(); + } + } +}; + +Neo.init2 = function() { + var pageview = document.getElementById("pageView"); + pageview.style.width = Neo.config.applet_width + "px"; + pageview.style.height = Neo.config.applet_height + "px"; + + Neo.canvas = document.getElementById("canvas"); + Neo.container = document.getElementById("container"); + Neo.toolsWrapper = document.getElementById("toolsWrapper"); + + Neo.painter = new Neo.Painter(); + Neo.painter.build(Neo.canvas, Neo.config.width, Neo.config.height); + + Neo.container.oncontextmenu = function() {return false;}; + + // 続きから描く + if (Neo.config.image_canvas) { + Neo.painter.loadImage(Neo.config.image_canvas); + } + + // 描きかけの画像が見つかったとき + if (sessionStorage.getItem('timestamp')) { + setTimeout(function () { + if (confirm("¿Cargar datos guardados?")) { + Neo.painter.loadSession(); + } + }, 1); + } + + window.addEventListener("beforeunload", function(e) { + if (!Neo.uploaded) { + Neo.painter.saveSession(); + } else { + Neo.painter.clearSession(); + } + }, false); +} + +Neo.initConfig = function(applet) { + if (applet) { + var name = applet.attributes.name.value || "neo"; + var appletWidth = applet.attributes.width; + var appletHeight = applet.attributes.height; + if (appletWidth) Neo.config.applet_width = parseInt(appletWidth.value); + if (appletHeight) Neo.config.applet_height = parseInt(appletHeight.value); + + var params = applet.getElementsByTagName('param'); + for (var i = 0; i < params.length; i++) { + var p = params[i]; + Neo.config[p.name] = Neo.fixConfig(p.value); + + if (p.name == "image_width") Neo.config.width = parseInt(p.value); + if (p.name == "image_height") Neo.config.height = parseInt(p.value); + } + + var e = document.getElementById("container"); + Neo.config.inherit_color = Neo.getInheritColor(e); + if (!Neo.config.color_frame) Neo.config.color_frame = Neo.config.color_text; + } + + Neo.config.reserves = [ + { size:1, + color:"#000000", alpha:1.0, + tool:Neo.Painter.TOOLTYPE_PEN, + drawType:Neo.Painter.DRAWTYPE_FREEHAND + }, + { size:5, + color:"#FFFFFF", alpha:1.0, + tool:Neo.Painter.TOOLTYPE_ERASER, + drawType:Neo.Painter.DRAWTYPE_FREEHAND + }, + { size:10, + color:"#FFFFFF", alpha:1.0, + tool:Neo.Painter.TOOLTYPE_ERASER, + drawType:Neo.Painter.DRAWTYPE_FREEHAND + }, + ]; + + Neo.reservePen = Neo.clone(Neo.config.reserves[0]); + Neo.reserveEraser = Neo.clone(Neo.config.reserves[1]); +}; + +Neo.fixConfig = function(value) { + // javaでは"#12345"を色として解釈するがjavascriptでは"#012345"に変換しないとだめ + if (value.match(/^#[0-9a-fA-F]{5}$/)) { + value = "#0" + value.slice(1); + } + return value; +}; + +Neo.initSkin = function() { + var sheet = document.styleSheets[0]; + if (!sheet) { + var style = document.createElement("style"); + document.head.appendChild(style); // must append before you can access sheet property + sheet = style.sheet; + } + + Neo.styleSheet = sheet; + + var lightBorder = Neo.multColor(Neo.config.color_icon, 1.3); + var darkBorder = Neo.multColor(Neo.config.color_icon, 0.7); + var lightBar = Neo.multColor(Neo.config.color_bar, 1.3); + var darkBar = Neo.multColor(Neo.config.color_bar, 0.7); + var bgImage = Neo.backgroundImage(); + + Neo.addRule(".NEO #container", "background-image", "url(" + bgImage + ")"); + Neo.addRule(".NEO .colorSlider .label", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .sizeSlider .label", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .layerControl .label1", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .layerControl .label0", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .toolTipOn .label", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .toolTipOff .label", "color", Neo.config.tool_color_text); + + Neo.addRule(".NEO #toolSet", "background-color", Neo.config.color_bk); + Neo.addRule(".NEO #tools", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .layerControl .bg", "border-bottom", "1px solid " + Neo.config.tool_color_text); + + Neo.addRule(".NEO .buttonOn", "color", Neo.config.color_text); + Neo.addRule(".NEO .buttonOff", "color", Neo.config.color_text); + + Neo.addRule(".NEO .buttonOff", "background-color", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff", "border-top", "1px solid ", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff", "border-left", "1px solid ", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff", "box-shadow", "0 0 0 1px " + Neo.config.color_icon + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO .buttonOff:hover", "background-color", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff:hover", "border-top", "1px solid " + lightBorder); + Neo.addRule(".NEO .buttonOff:hover", "border-left", "1px solid " + lightBorder); + Neo.addRule(".NEO .buttonOff:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "background-color", darkBorder); + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-top", "1px solid " + darkBorder); + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-left", "1px solid " + darkBorder); + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO #canvas", "border", "1px solid " + Neo.config.color_frame); + Neo.addRule(".NEO #scrollH, .NEO #scrollV", "background-color", Neo.config.color_icon); + Neo.addRule(".NEO #scrollH, .NEO #scrollV", "box-shadow", "0 0 0 1px white" + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "background-color", Neo.config.color_bar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "box-shadow", "0 0 0 1px " + Neo.config.color_icon); + Neo.addRule(".NEO #scrollH div:hover, .NEO #scrollV div:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect); + + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-top", "1px solid " + lightBar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-left", "1px solid " + lightBar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-right", "1px solid " + darkBar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-bottom", "1px solid " + darkBar); + + Neo.addRule(".NEO .toolTipOn", "background-color", Neo.multColor(Neo.config.tool_color_button, 0.7)); + Neo.addRule(".NEO .toolTipOff", "background-color", Neo.config.tool_color_button); + Neo.addRule(".NEO .toolTipFixed", "background-color", Neo.config.tool_color_button2); + + Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "background-color", Neo.config.tool_color_bar); + Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar); + Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar); + Neo.addRule(".NEO .layerControl", "background-color", Neo.config.tool_color_bar); + + Neo.addRule(".NEO .colorTipOn, .NEO .colorTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .toolTipOn, .NEO .toolTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .toolTipFixed", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .reserveControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .layerControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .reserveControl .reserve", "border", "1px solid " + Neo.config.tool_color_frame); +}; + +Neo.addRule = function(selector, styleName, value, sheet) { + if (!sheet) sheet = Neo.styleSheet; + if (sheet.addRule) { + sheet.addRule(selector, styleName + ":" + value, sheet.rules.length); + + } else if (sheet.insertRule) { + var rule = selector + "{" + styleName + ":" + value + "}"; + var index = sheet.cssRules.length; + sheet.insertRule(rule, index); + } +}; + +Neo.getInheritColor = function(e) { + var result = "#000000"; + while (e && e.style) { + if (e.style.color != "") { + result = e.style.color; + break; + } + if (e.attributes["text"]) { + result = e.attributes["text"].value; + break; + } + e = e.parentNode; + } + return result; +}; + +Neo.backgroundImage = function() { + var c1 = Neo.painter.getColor(Neo.config.color_bk) | 0xff000000; + var c2 = Neo.painter.getColor(Neo.config.color_bk2) | 0xff000000; + var bgCanvas = document.createElement("canvas"); + bgCanvas.width = 16; + bgCanvas.height = 16; + var ctx = bgCanvas.getContext("2d"); + var imageData = ctx.getImageData(0, 0, 16, 16); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var index = 0; + for (var y = 0; y < 16; y++) { + for (var x = 0; x < 16; x++) { + buf32[index++] = (x == 14 || y == 14) ? c2 : c1; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + return bgCanvas.toDataURL('image/png'); +}; + +Neo.multColor = function(c, scale) { + var r = Math.round(parseInt(c.substr(1, 2), 16) * scale); + var g = Math.round(parseInt(c.substr(3, 2), 16) * scale); + var b = Math.round(parseInt(c.substr(5, 2), 16) * scale); + r = ("0" + Math.min(Math.max(r, 0), 255).toString(16)).substr(-2); + g = ("0" + Math.min(Math.max(g, 0), 255).toString(16)).substr(-2); + b = ("0" + Math.min(Math.max(b, 0), 255).toString(16)).substr(-2); + return '#' + r + g + b; +}; + +Neo.initComponents = function() { + document.getElementById("copyright").innerHTML += "v" + Neo.version; + + //アプレットのborderの動作をエミュレート + if (navigator.userAgent.search("FireFox") > -1) { + var container = document.getElementById("container"); + container.addEventListener("mousedown", function(e) { + container.style.borderColor = Neo.config.inherit_color; + e.stopPropagation(); + }, false); + document.addEventListener("mousedown", function(e) { + container.style.borderColor = 'transparent'; + }, false); + } + + // 投稿に失敗する可能性があるときは警告を表示する + Neo.showWarning(); + + if (Neo.styleSheet) { + Neo.addRule("*", "user-select", "none"); + Neo.addRule("*", "-webkit-user-select", "none"); + Neo.addRule("*", "-ms-user-select", "none"); + } +} + +Neo.initButtons = function() { + new Neo.Button().init("undo").onmouseup = function() { + new Neo.UndoCommand(Neo.painter).execute(); + }; + new Neo.Button().init("redo").onmouseup = function () { + new Neo.RedoCommand(Neo.painter).execute(); + }; + new Neo.Button().init("window").onmouseup = function() { + new Neo.WindowCommand(Neo.painter).execute(); + }; + new Neo.Button().init("submit").onmouseup = function() { + new Neo.SubmitCommand(Neo.painter).execute(); + }; + new Neo.Button().init("copyright").onmouseup = function() { + new Neo.CopyrightCommand(Neo.painter).execute(); + }; + new Neo.Button().init("zoomPlus").onmouseup = function() { + new Neo.ZoomPlusCommand(Neo.painter).execute(); + }; + new Neo.Button().init("zoomMinus").onmouseup = function() { + new Neo.ZoomMinusCommand(Neo.painter).execute(); + }; + + Neo.fillButton = new Neo.Button().init("fill", {type:'fill'}); + + // toolTip + Neo.penTip = new Neo.PenTip().init("pen"); + Neo.pen2Tip = new Neo.Pen2Tip().init("pen2"); + Neo.effectTip = new Neo.EffectTip().init("effect"); + Neo.effect2Tip = new Neo.Effect2Tip().init("effect2"); + Neo.eraserTip = new Neo.EraserTip().init("eraser"); + Neo.drawTip = new Neo.DrawTip().init("draw"); + Neo.maskTip = new Neo.MaskTip().init("mask"); + + Neo.toolButtons = [Neo.fillButton, + Neo.penTip, + Neo.pen2Tip, + Neo.effectTip, + Neo.effect2Tip, + Neo.drawTip, + Neo.eraserTip]; + + // colorTip + for (var i = 1; i <= 14; i++) { + new Neo.ColorTip().init("color" + i, {index:i}); + }; + + // colorSlider + Neo.sliders[Neo.SLIDERTYPE_RED] = new Neo.ColorSlider().init( + "sliderRed", {type:Neo.SLIDERTYPE_RED}); + Neo.sliders[Neo.SLIDERTYPE_GREEN] = new Neo.ColorSlider().init( + "sliderGreen", {type:Neo.SLIDERTYPE_GREEN}); + Neo.sliders[Neo.SLIDERTYPE_BLUE] = new Neo.ColorSlider().init( + "sliderBlue", {type:Neo.SLIDERTYPE_BLUE}); + Neo.sliders[Neo.SLIDERTYPE_ALPHA] = new Neo.ColorSlider().init( + "sliderAlpha", {type:Neo.SLIDERTYPE_ALPHA}); + + // sizeSlider + Neo.sliders[Neo.SLIDERTYPE_SIZE] = new Neo.SizeSlider().init( + "sliderSize", {type:Neo.SLIDERTYPE_SIZE}); + + // reserveControl + for (var i = 1; i <= 3; i++) { + new Neo.ReserveControl().init("reserve" + i, {index:i}); + }; + + new Neo.LayerControl().init("layerControl"); + new Neo.ScrollBarButton().init("scrollH"); + new Neo.ScrollBarButton().init("scrollV"); +}; + +Neo.start = function(isApp) { + if (!Neo.painter) return; + + Neo.initSkin(); + Neo.initComponents(); + Neo.initButtons(); + + Neo.isApp = isApp; + if (Neo.applet) { + var name = Neo.applet.attributes.name.value || "paintbbs"; + Neo.applet.outerHTML = ""; + document[name] = Neo; + + Neo.resizeCanvas(); + Neo.container.style.visibility = "visible"; + + if (Neo.isApp) { + var ipc = require('electron').ipcRenderer; + ipc.sendToHost('neo-status', 'ok'); + } + } +}; + +Neo.showWarning = function() { + var futaba = location.hostname.match(/2chan.net/i); + var samplebbs = location.hostname.match(/neo.websozai.jp/i); + + var chrome = navigator.userAgent.match(/Chrome\/(\d+)/i); + if (chrome && chrome.length > 1) chrome = chrome[1]; + + var edge = navigator.userAgent.match(/Edge\/(\d+)/i); + if (edge && edge.length > 1) edge = edge[1]; + + var ms = false; + if (/MSIE 10/i.test(navigator.userAgent)) { + ms = true; // This is internet explorer 10 + } + if (/MSIE 9/i.test(navigator.userAgent) || + /rv:11.0/i.test(navigator.userAgent)) { + ms = true; // This is internet explorer 9 or 11 + } + + var str = ""; + if (futaba || samplebbs) { + if (ms || (edge && edge < 15)) { + str = "このブラウザでは<br>投稿に失敗することがあります<br>"; + } + } + + // もし<PARAM NAME="neo_warning" VALUE="...">があれば表示する + if (Neo.config.neo_warning) { + str += Neo.config.neo_warning; + } + + var warning = document.getElementById("neoWarning") + warning.innerHTML = str; + setTimeout(function() { warning.style.opacity = "0"; }, 15000); +}; + +/* +----------------------------------------------------------------------- +UIの更新 +----------------------------------------------------------------------- +*/ + +Neo.updateUI = function() { + var current = Neo.painter.tool.getToolButton(); + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + if (current) { + if (current == toolTip) { + toolTip.setSelected(true); + toolTip.update(); + } else { + toolTip.setSelected(false); + } + } + } + if (Neo.drawTip) { + Neo.drawTip.update(); + } + + Neo.updateUIColor(true, false); +} + +Neo.updateUIColor = function(updateSlider, updateColorTip) { + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + toolTip.update(); + } + + if (updateSlider) { + for (var i = 0; i < Neo.sliders.length; i++) { + var slider = Neo.sliders[i]; + slider.update(); + } + } + + // パレットを変更するとき + if (updateColorTip) { + var colorTip = Neo.ColorTip.getCurrent(); + if (colorTip) { + colorTip.setColor(Neo.painter.foregroundColor); + } + } +}; + +/* +----------------------------------------------------------------------- +リサイズ対応 +----------------------------------------------------------------------- +*/ + +Neo.updateWindow = function() { + if (Neo.fullScreen) { + document.getElementById("windowView").style.display = "block"; + document.getElementById("windowView").appendChild(Neo.container); + + } else { + document.getElementById("windowView").style.display = "none"; + document.getElementById("pageView").appendChild(Neo.container); + } + Neo.resizeCanvas(); +}; + +Neo.resizeCanvas = function() { + var appletWidth = Neo.container.clientWidth; + var appletHeight = Neo.container.clientHeight; + + var canvasWidth = Neo.painter.canvasWidth; + var canvasHeight = Neo.painter.canvasHeight; + + var width0 = canvasWidth * Neo.painter.zoom; + var height0 = canvasHeight * Neo.painter.zoom; + + var width = (width0 < appletWidth - 100) ? width0 : appletWidth - 100; + var height = (height0 < appletHeight - 120) ? height0 : appletHeight - 120; + + //width, heightは偶数でないと誤差が出るため + width = Math.floor(width / 2) * 2; + height = Math.floor(height / 2) * 2; + + Neo.painter.destWidth = width; + Neo.painter.destHeight = height; + + Neo.painter.destCanvas.width = width; + Neo.painter.destCanvas.height = height; + Neo.painter.destCanvasCtx = Neo.painter.destCanvas.getContext("2d"); + Neo.painter.destCanvasCtx.imageSmoothingEnabled = false; + Neo.painter.destCanvasCtx.mozImageSmoothingEnabled = false; + + Neo.canvas.style.width = width + "px"; + Neo.canvas.style.height = height + "px"; + + var top = (Neo.container.clientHeight - toolsWrapper.clientHeight) / 2; + Neo.toolsWrapper.style.top = ((top > 0) ? top : 0) + "px"; + + if (top < 0) { + var s = Neo.container.clientHeight / toolsWrapper.clientHeight; + Neo.toolsWrapper.style.transform = + "translate(0, " + top + "px) scale(1," + s + ")"; + } else { + Neo.toolsWrapper.style.transform = ""; + } + + Neo.painter.setZoom(Neo.painter.zoom); + Neo.painter.updateDestCanvas(0, 0, canvasWidth, canvasHeight); +}; + +/* +----------------------------------------------------------------------- +投稿 +----------------------------------------------------------------------- +*/ + +Neo.clone = function(src) { + var dst = {}; + for (var k in src) { + dst[k] = src[k]; + } + return dst; +}; + +Neo.getSizeString = function(len) { + var result = String(len); + while (result.length < 8) { + result = "0" + result; + } + return result; +}; + +Neo.openURL = function(url) { + if (Neo.isApp) { + require('electron').shell.openExternal(url); + + } else { + location.href = url; + } +}; + +Neo.submit = function(board, blob, thumbnail, thumbnail2) { + var url = Neo.config.url_save; + console.log("submit url=" + url); + + var headerString = Neo.config.send_header || ""; + var imageType = Neo.config.send_header_image_type; + if (imageType && imageType == "true") { + headerString = "image_type=png&" + headerString + console.log("header=" + headerString); + } + + var header = new Blob([headerString]); + var headerLength = this.getSizeString(header.size); + var imgLength = this.getSizeString(blob.size); + + var array = ['P', // PaintBBS + headerLength, + header, + imgLength, + '\r\n', + blob]; + + if (thumbnail) { + var thumbnailLength = this.getSizeString(thumbnail.size); + array.push(thumbnailLength, thumbnail); + } + if (thumbnail2) { + var thumbnail2Length = this.getSizeString(thumbnail2.size); + array.push(thumbnail2Length, thumbnail2); + } + + var body = new Blob(array, {type: 'application/octet-binary'}); //これが必要!! + + var request = new XMLHttpRequest(); + request.open("POST", url, true); + + request.onload = function(e) { + console.log(request.response); + Neo.uploaded = true; + + var url = Neo.config.url_exit; + /*if (url[0] == '/') { + url = url.replace(/^.*\//, ''); //よくわかんないけどとりあえず + }*/ + + // ふたばのpaintpost.phpは、画像投稿に成功するとresponseに + // "./futaba.php?mode=paintcom&painttmp=.png" + // という文字列を返します。 + // + // NEOでは、responseに文字列"painttmp="が含まれる場合は + // <PARAM>で指定されたurl_exitを無視して、このURLにジャンプします。 + var responseURL = request.response.replace(/&/g, '&'); + if (responseURL.match(/painttmp=/)) { + url = responseURL; + } + //var exitURL = board + url; + var exitURL = url; + + // しぃちゃんのドキュメントをよく見たら + // responseが "URL:〜" の形だった場合はそこへ飛ばすって書いてありました。 + // こっちを使うべきでした…… + if (responseURL.match(/^URL:/)) { + exitURL = responseURL.replace(/^URL:/, ''); + } + + location.href = exitURL; + }; + request.onerror = function(e) { + console.log("error"); + }; + request.onabort = function(e) { + console.log("abort"); + }; + request.ontimeout = function(e) { + console.log("timeout"); + }; + + if (0) { // データのデバッグのため送信するデータをuint8arrayにコピーしておく + var fr = new FileReader(); + fr.onload = function () { + var result = fr.result; + } + fr.readAsArrayBuffer(body); + } + + request.send(body); +}; + +/* +----------------------------------------------------------------------- +LiveConnect +----------------------------------------------------------------------- +*/ + +Neo.getColors = function() { + console.log("getColors"); + return Neo.config.colors.join('\n'); +}; + +Neo.setColors = function(colors) { + console.log("setColors"); + var array = colors.split('\n'); + for (var i = 0; i < 14; i++) { + var color = array[i]; + Neo.config.colors[i] = color; + Neo.colorTips[i].setColor(color); + } +}; + +/* +----------------------------------------------------------------------- +DOMツリーの作成 +----------------------------------------------------------------------- +*/ + +Neo.createContainer = function(applet) { + var neo = document.createElement("div"); + neo.className = "NEO"; + neo.id = "NEO"; + neo.innerHTML = (function() {/* + +<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> + +<div id="pageView" style="width:450px; height:470px; margin:auto;"> + <div id="container" style="visibility:hidden;"> + <div id="center"> + <div id="painterContainer"> + <div id="painterWrapper"> + <div id="upper"> + <div id="redo">Rehacer</div> + <div id="undo">Deshacer</div> + <div id="fill">Llenar</div> + </div> + <div id="painter"> + <div id="canvas"> + <div id="scrollH"></div> + <div id="scrollV"></div> + <div id="zoomPlusWrapper"> + <div id="zoomPlus">+</div> + </div> + <div id="zoomMinusWrapper"> + <div id="zoomMinus">-</div> + </div> + <div id="neoWarning"></div> + </div> + </div> + <div id="lower"> + </div> + </div> + <div id="toolsWrapper"> + <div id="tools"> + <div id="toolSet"> + <div id="pen"></div> + <div id="pen2"></div> + <div id="effect"></div> + <div id="effect2"></div> + <div id="eraser"></div> + <div id="draw"></div> + <div id="mask"></div> + + <div class="colorTips"> + <div id="color2"></div><div id="color1"></div><br> + <div id="color4"></div><div id="color3"></div><br> + <div id="color6"></div><div id="color5"></div><br> + <div id="color8"></div><div id="color7"></div><br> + <div id="color10"></div><div id="color9"></div><br> + <div id="color12"></div><div id="color11"></div><br> + <div id="color14"></div><div id="color13"></div> + </div> + + <div id="sliderRed"></div> + <div id="sliderGreen"></div> + <div id="sliderBlue"></div> + <div id="sliderAlpha"></div> + <div id="sliderSize"></div> + + <div class="reserveControl" style="margin-top:4px;"> + <div id="reserve1"></div> + <div id="reserve2"></div> + <div id="reserve3"></div> + </div> + <div id="layerControl" style="margin-top:6px;"></div> + + <!--<div id="toolPad" style="height:20px;"></div>--> + </div> + </div> + </div> + </div> + </div> + <div id="headerButtons"> + <div id="window">Ventana</div> + </div> + <div id="footerButtons"> + <div id="submit">Enviar</div> + <div id="copyright">(C)しいちゃん PaintBBS NEO</div> + </div> + </div> +</div> + +<div id="windowView" style="display: none;"> + +</div> + + +*/}).toString().match(/\/\*([^]*)\*\//)[1]; + + var parent = applet.parentNode; + parent.appendChild(neo); + parent.insertBefore(neo, applet); + +// applet.style.display = "none"; + + // NEOを組み込んだURLをアプリ版で開くとDOMツリーが2重にできて格好悪いので消しておく + setTimeout(function() { + var tmp = document.getElementsByClassName("NEO"); + if (tmp.length > 1) { + for (var i = 1; i < tmp.length; i++) { + tmp[i].style.display = "none"; + } + } + }, 0); +}; + + +'use strict'; + +Neo.Painter = function() { + this._undoMgr = new Neo.UndoManager(50); +}; + +Neo.Painter.prototype.container; +Neo.Painter.prototype._undoMgr; +Neo.Painter.prototype.tool; +Neo.Painter.prototype.inputText; + +//Canvas Info +Neo.Painter.prototype.canvasWidth; +Neo.Painter.prototype.canvasHeight; +Neo.Painter.prototype.canvas = []; +Neo.Painter.prototype.canvasCtx = []; +Neo.Painter.prototype.visible = []; +Neo.Painter.prototype.current = 0; + +//Temp Canvas Info +Neo.Painter.prototype.tempCanvas; +Neo.Painter.prototype.tempCanvasCtx; +Neo.Painter.prototype.tempX = 0; +Neo.Painter.prototype.tempY = 0; + +//Destination Canvas for display +Neo.Painter.prototype.destCanvas; +Neo.Painter.prototype.destCanvasCtx; + + +Neo.Painter.prototype.backgroundColor = "#ffffff"; +Neo.Painter.prototype.foregroundColor = "#000000"; + +Neo.Painter.prototype.lineWidth = 1; +Neo.Painter.prototype.alpha = 1; +Neo.Painter.prototype.zoom = 1; +Neo.Painter.prototype.zoomX = 0; +Neo.Painter.prototype.zoomY = 0; + +Neo.Painter.prototype.isMouseDown; +Neo.Painter.prototype.isMouseDownRight; +Neo.Painter.prototype.prevMouseX; +Neo.Painter.prototype.prevMouseY; +Neo.Painter.prototype.mouseX; +Neo.Painter.prototype.mouseY; + +Neo.Painter.prototype.slowX = 0; +Neo.Painter.prototype.slowY = 0; +Neo.Painter.prototype.stab = null; + +Neo.Painter.prototype.isShiftDown = false; +Neo.Painter.prototype.isCtrlDown = false; +Neo.Painter.prototype.isAltDown = false; + +//Neo.Painter.prototype.onUpdateCanvas; +Neo.Painter.prototype._roundData = []; +Neo.Painter.prototype._toneData = []; +Neo.Painter.prototype.toolStack = []; + +Neo.Painter.prototype.maskType = 0; +Neo.Painter.prototype.drawType = 0; +Neo.Painter.prototype.maskColor = "#000000"; +Neo.Painter.prototype._currentColor = []; +Neo.Painter.prototype._currentMask = []; + +Neo.Painter.prototype.aerr; + +Neo.Painter.LINETYPE_NONE = 0; +Neo.Painter.LINETYPE_PEN = 1; +Neo.Painter.LINETYPE_ERASER = 2; +Neo.Painter.LINETYPE_BRUSH = 3; +Neo.Painter.LINETYPE_TONE = 4; +Neo.Painter.LINETYPE_DODGE = 5; +Neo.Painter.LINETYPE_BURN = 6; + +Neo.Painter.MASKTYPE_NONE = 0; +Neo.Painter.MASKTYPE_NORMAL = 1; +Neo.Painter.MASKTYPE_REVERSE = 2; +Neo.Painter.MASKTYPE_ADD = 3; +Neo.Painter.MASKTYPE_SUB = 4; + +Neo.Painter.DRAWTYPE_FREEHAND = 0; +Neo.Painter.DRAWTYPE_LINE = 1; +Neo.Painter.DRAWTYPE_BEZIER = 2; + +Neo.Painter.ALPHATYPE_NONE = 0; +Neo.Painter.ALPHATYPE_PEN = 1; +Neo.Painter.ALPHATYPE_FILL = 2; +Neo.Painter.ALPHATYPE_BRUSH = 3; + +Neo.Painter.TOOLTYPE_NONE = 0; +Neo.Painter.TOOLTYPE_PEN = 1; +Neo.Painter.TOOLTYPE_ERASER = 2; +Neo.Painter.TOOLTYPE_HAND = 3; +Neo.Painter.TOOLTYPE_SLIDER = 4; +Neo.Painter.TOOLTYPE_FILL = 5; +Neo.Painter.TOOLTYPE_MASK = 6; +Neo.Painter.TOOLTYPE_ERASEALL = 7; +Neo.Painter.TOOLTYPE_ERASERECT = 8; +Neo.Painter.TOOLTYPE_COPY = 9; +Neo.Painter.TOOLTYPE_PASTE = 10; +Neo.Painter.TOOLTYPE_MERGE = 11; +Neo.Painter.TOOLTYPE_FLIP_H = 12; +Neo.Painter.TOOLTYPE_FLIP_V = 13; + +Neo.Painter.TOOLTYPE_BRUSH = 14; +Neo.Painter.TOOLTYPE_TEXT = 15; +Neo.Painter.TOOLTYPE_TONE = 16; +Neo.Painter.TOOLTYPE_BLUR = 17; +Neo.Painter.TOOLTYPE_DODGE = 18; +Neo.Painter.TOOLTYPE_BURN = 19; +Neo.Painter.TOOLTYPE_RECT = 20; +Neo.Painter.TOOLTYPE_RECTFILL = 21; +Neo.Painter.TOOLTYPE_ELLIPSE = 22; +Neo.Painter.TOOLTYPE_ELLIPSEFILL = 23; +Neo.Painter.TOOLTYPE_BLURRECT = 24; +Neo.Painter.TOOLTYPE_TURN = 25; + +Neo.Painter.prototype.build = function(div, width, height) +{ + this.container = div; + this._initCanvas(div, width, height); + this._initRoundData(); + this._initToneData(); + this._initInputText(); + + this.setTool(new Neo.PenTool()); + +}; + +Neo.Painter.prototype.setTool = function(tool) { + if (this.tool && this.tool.saveStates) this.tool.saveStates(); + + if (this.tool && this.tool.kill) { + this.tool.kill(); + } + this.tool = tool; + tool.init(); + if (this.tool && this.tool.loadStates) this.tool.loadStates(); +}; + +Neo.Painter.prototype.pushTool = function(tool) { + this.toolStack.push(this.tool); + this.tool = tool; + tool.init(); +}; + +Neo.Painter.prototype.popTool = function() { + var tool = this.tool; + if (tool && tool.kill) { + tool.kill(); + } + this.tool = this.toolStack.pop(); +}; + +Neo.Painter.prototype.getCurrentTool = function() { + if (this.tool) { + var tool = this.tool; + if (tool && tool.type == Neo.Painter.TOOLTYPE_SLIDER) { + var stack = this.toolStack; + if (stack.length > 0) { + tool = stack[stack.length - 1]; + } + } + return tool; + } + return null; +}; + +Neo.Painter.prototype.setToolByType = function(toolType) { + switch (parseInt(toolType)) { + case Neo.Painter.TOOLTYPE_PEN: this.setTool(new Neo.PenTool()); break; + case Neo.Painter.TOOLTYPE_ERASER: this.setTool(new Neo.EraserTool()); break; + case Neo.Painter.TOOLTYPE_HAND: this.setTool(new Neo.HandTool()); break; + case Neo.Painter.TOOLTYPE_FILL: this.setTool(new Neo.FillTool()); break; + case Neo.Painter.TOOLTYPE_ERASEALL: this.setTool(new Neo.EraseAllTool()); break; + case Neo.Painter.TOOLTYPE_ERASERECT: this.setTool(new Neo.EraseRectTool()); break; + + case Neo.Painter.TOOLTYPE_COPY: this.setTool(new Neo.CopyTool()); break; + case Neo.Painter.TOOLTYPE_PASTE: this.setTool(new Neo.PasteTool()); break; + case Neo.Painter.TOOLTYPE_MERGE: this.setTool(new Neo.MergeTool()); break; + case Neo.Painter.TOOLTYPE_FLIP_H: this.setTool(new Neo.FlipHTool()); break; + case Neo.Painter.TOOLTYPE_FLIP_V: this.setTool(new Neo.FlipVTool()); break; + + case Neo.Painter.TOOLTYPE_BRUSH: this.setTool(new Neo.BrushTool()); break; + case Neo.Painter.TOOLTYPE_TEXT: this.setTool(new Neo.TextTool()); break; + case Neo.Painter.TOOLTYPE_TONE: this.setTool(new Neo.ToneTool()); break; + case Neo.Painter.TOOLTYPE_BLUR: this.setTool(new Neo.BlurTool()); break; + case Neo.Painter.TOOLTYPE_DODGE: this.setTool(new Neo.DodgeTool()); break; + case Neo.Painter.TOOLTYPE_BURN: this.setTool(new Neo.BurnTool()); break; + + case Neo.Painter.TOOLTYPE_RECT: this.setTool(new Neo.RectTool()); break; + case Neo.Painter.TOOLTYPE_RECTFILL: this.setTool(new Neo.RectFillTool()); break; + case Neo.Painter.TOOLTYPE_ELLIPSE: this.setTool(new Neo.EllipseTool()); break; + case Neo.Painter.TOOLTYPE_ELLIPSEFILL:this.setTool(new Neo.EllipseFillTool()); break; + case Neo.Painter.TOOLTYPE_BLURRECT: this.setTool(new Neo.BlurRectTool()); break; + case Neo.Painter.TOOLTYPE_TURN: this.setTool(new Neo.TurnTool()); break; + + default: + console.log("unknown toolType " + toolType); + break; + } +}; + +Neo.Painter.prototype._initCanvas = function(div, width, height) { + width = parseInt(width); + height = parseInt(height); + var destWidth = parseInt(div.clientWidth); + var destHeight = parseInt(div.clientHeight); + this.destWidth = width; + this.destHeight = height; + + this.canvasWidth = width; + this.canvasHeight = height; + this.zoomX = width * 0.5; + this.zoomY = height * 0.5; + + for (var i = 0; i < 2; i++) { + this.canvas[i] = document.createElement("canvas"); + this.canvas[i].width = width; + this.canvas[i].height = height; + this.canvasCtx[i] = this.canvas[i].getContext("2d"); + + this.canvas[i].style.imageRendering = "pixelated"; + this.canvasCtx[i].imageSmoothingEnabled = false; + this.canvasCtx[i].mozImageSmoothingEnabled = false; + this.visible[i] = true; + } + + this.tempCanvas = document.createElement("canvas"); + this.tempCanvas.width = width; + this.tempCanvas.height = height; + this.tempCanvasCtx = this.tempCanvas.getContext("2d"); + this.tempCanvas.style.position = "absolute"; + this.tempCanvas.enabled = false; + + var array = this.container.getElementsByTagName("canvas"); + if (array.length > 0) { + this.destCanvas = array[0]; + } else { + this.destCanvas = document.createElement("canvas"); + this.container.appendChild(this.destCanvas); + } + + this.destCanvasCtx = this.destCanvas.getContext("2d"); + this.destCanvas.width = destWidth; + this.destCanvas.height = destHeight; + + this.destCanvas.style.imageRendering = "pixelated"; + this.destCanvasCtx.imageSmoothingEnabled = false; + this.destCanvasCtx.mozImageSmoothingEnabled = false; + + var ref = this; + + var container = document.getElementById("container"); + + if (window.PointerEvent) { + container.addEventListener("pointerdown", function(e) { + ref._mouseDownHandler(e); }); + container.addEventListener("pointerup", function(e) { + ref._mouseUpHandler(e); }); + container.addEventListener("pointermove", function(e) { + ref._mouseMoveHandler(e); }); + container.addEventListener("pointerover", function(e) { + ref._rollOverHandler(e); }); + container.addEventListener("pointerout", function(e) { + ref._rollOutHandler(e); }); + + } else { + container.onmousedown = function(e) {ref._mouseDownHandler(e)}; + container.onmousemove = function(e) {ref._mouseMoveHandler(e)}; + container.onmouseup = function(e) {ref._mouseUpHandler(e)}; + container.onmouseover = function(e) {ref._rollOverHandler(e)}; + container.onmouseout = function(e) {ref._rollOutHandler(e)}; + + container.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + }, true); + container.addEventListener("touchmove", function(e) { + ref._mouseMoveHandler(e); + }, true); + container.addEventListener("touchend", function(e) { + ref._mouseUpHandler(e); + }, true); + } + + document.onkeydown = function(e) {ref._keyDownHandler(e)}; + document.onkeyup = function(e) {ref._keyUpHandler(e)}; + + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype._initRoundData = function() { + for (var r = 1; r <= 30; r++) { + this._roundData[r] = new Uint8Array(r * r); + var mask = this._roundData[r]; + var d = Math.floor(r / 2.0); + var index = 0; + for (var x = 0; x < r; x++) { + for (var y = 0; y < r; y++) { + var xx = x + 0.5 - r/2.0; + var yy = y + 0.5 - r/2.0; + mask[index++] = (xx*xx + yy*yy <= r*r/4) ? 1 : 0; + } + } + } + this._roundData[3][0] = 0; + this._roundData[3][2] = 0; + this._roundData[3][6] = 0; + this._roundData[3][8] = 0; + + this._roundData[5][1] = 0; + this._roundData[5][3] = 0; + this._roundData[5][5] = 0; + this._roundData[5][9] = 0; + this._roundData[5][15] = 0; + this._roundData[5][19] = 0; + this._roundData[5][21] = 0; + this._roundData[5][23] = 0; +}; + +Neo.Painter.prototype._initToneData = function() { + var pattern = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5]; + + for (var i = 0; i < 16; i++) { + this._toneData[i] = new Uint8Array(16); + for (var j = 0; j < 16; j++) { + this._toneData[i][j] = (i >= pattern[j]) ? 1 : 0; + } + } +}; + +Neo.Painter.prototype.getToneData = function(alpha) { + var alphaTable = [23, + 47, + 69, + 92, + 114, + 114, + 114, + 138, + 161, + 184, + 184, + 207, + 230, + 230, + 253, + ]; + + for (var i = 0; i < alphaTable.length; i++) { + if (alpha < alphaTable[i]) { + return this._toneData[i]; + } + } + return this._toneData[i]; +}; + +Neo.Painter.prototype._initInputText = function() { + var text = document.getElementById("inputtext"); + if (!text) { + text = document.createElement("div"); + } + + text.id = "inputext"; + text.setAttribute("contentEditable", true); + text.spellcheck = false; + text.className = "inputText"; + text.innerHTML = ""; + + text.style.display = "none"; +// text.style.userSelect = "none"; + Neo.painter.container.appendChild(text); + this.inputText = text; + + this.updateInputText(); +}; + +Neo.Painter.prototype.hideInputText = function() { + var text = this.inputText; + text.blur(); + text.style.display = "none"; +}; + +Neo.Painter.prototype.updateInputText = function() { + var text = this.inputText; + var d = this.lineWidth; + var fontSize = Math.round(d * 55/28 + 7); + var height = Math.round(d * 68/28 + 12); + + text.style.fontSize = fontSize + "px"; + text.style.lineHeight = fontSize + "px"; + text.style.height = fontSize + "px"; + text.style.marginTop = -fontSize + "px"; +}; + +/* +----------------------------------------------------------------------- + Mouse Event Handling +----------------------------------------------------------------------- +*/ + +Neo.Painter.prototype._keyDownHandler = function(e) { + this.isShiftDown = e.shiftKey; + this.isCtrlDown = e.ctrlKey; + this.isAltDown = e.altKey; + if (e.keyCode == 32) this.isSpaceDown = true; + + if (!this.isShiftDown && this.isCtrlDown) { + if (!this.isAltDown) { + if (e.keyCode == 90 || e.keyCode == 85) this.undo(); //Ctrl+Z,Ctrl.U + if (e.keyCode == 89) this.redo(); //Ctrl+Y + } else { + if (e.keyCode == 90) this.redo(); //Ctrl+Alt+Z + } + } + + if (!this.isShiftDown && !this.isCtrlDown && !this.isAltDown) { + if (e.keyCode == 107) new Neo.ZoomPlusCommand(this).execute(); // + + if (e.keyCode == 109) new Neo.ZoomMinusCommand(this).execute(); // - + } + + if (this.tool.keyDownHandler) { + this.tool.keyDownHandler(e); + } + + //スペース・Shift+スペースででスクロールしないように + if (document.activeElement != this.inputText) e.preventDefault(); +}; + +Neo.Painter.prototype._keyUpHandler = function(e) { + this.isShiftDown = e.shiftKey; + this.isCtrlDown = e.ctrlKey; + this.isAltDown = e.altKey; + if (e.keyCode == 32) this.isSpaceDown = false; + + if (this.tool.keyUpHandler) { + this.tool.keyUpHandler(oe); + } +}; + +Neo.Painter.prototype._rollOverHandler = function(e) { + if (this.tool.rollOverHandler) { + this.tool.rollOverHandler(this); + } +}; + +Neo.Painter.prototype._rollOutHandler = function(e) { + if (this.tool.rollOutHandler) { + this.tool.rollOutHandler(this); + } +}; + +Neo.Painter.prototype._mouseDownHandler = function(e) { + if (e.target == Neo.painter.destCanvas) { + //よくわからないがChromeでドラッグの時カレットが出るのを防ぐ + //http://stackoverflow.com/questions/2745028/chrome-sets-cursor-to-text-while-dragging-why + e.preventDefault(); + } + + if (e.button == 2) { + this.isMouseDownRight = true; + + } else { + if (!e.shiftKey && e.ctrlKey && e.altKey) { + this.isMouseDown = true; + + } else { + if (e.ctrlKey || e.altKey) { + this.isMouseDownRight = true; + } else { + this.isMouseDown = true; + } + } + } + + this._updateMousePosition(e); + this.prevMouseX = this.mouseX; + this.prevMouseY = this.mouseY; + + if (this.isMouseDownRight) { + this.isMouseDownRight = false; + if (!this.isWidget(e.target)) { + this.pickColor(this.mouseX, this.mouseY); + return; + } + } + + if (!this.isUIPaused()) { + if (e.target['data-bar']) { + this.pushTool(new Neo.HandTool()); + + } else if (this.isSpaceDown && document.activeElement != this.inputText) { + this.pushTool(new Neo.HandTool()); + this.tool.reverse = true; + + } else if (e.target['data-slider'] != undefined) { + this.pushTool(new Neo.SliderTool()); + this.tool.target = e.target; + + } else if (e.ctrlKey && e.altKey && !e.shiftKey) { + this.pushTool(new Neo.SliderTool()); + this.tool.target = Neo.sliders[Neo.SLIDERTYPE_SIZE].element; + this.tool.alt = true; + + } else if (this.isWidget(e.target)) { + this.isMouseDown = false; + this.pushTool(new Neo.DummyTool()); + } + } + this.tool.downHandler(this); + + var ref = this; + document.onmouseup = function(e) { + ref._mouseUpHandler(e) + }; +}; + +Neo.Painter.prototype._mouseUpHandler = function(e) { + this.isMouseDown = false; + this.isMouseDownRight = false; + this.tool.upHandler(this); + document.onmouseup = undefined; +}; + +Neo.Painter.prototype._mouseMoveHandler = function(e) { + this._updateMousePosition(e); + + if (this.isMouseDown || this.isMouseDownRight) { + this.tool.moveHandler(this); + } else { + if (this.tool.upMoveHandler) { + this.tool.upMoveHandler(this); + } + } + this.prevMouseX = this.mouseX; + this.prevMouseY = this.mouseY; +}; + + +Neo.Painter.prototype._updateMousePosition = function(e) { + var rect = this.destCanvas.getBoundingClientRect(); + var x = (e.clientX !== undefined) ? e.clientX : e.touches[0].clientX; + var y = (e.clientY !== undefined) ? e.clientY : e.touches[0].clientY; + + if (this.zoom <= 0) this.zoom = 1; //なぜか0になることがあるので + + this.mouseX = (x - rect.left) / this.zoom + + this.zoomX + - this.destCanvas.width * 0.5 / this.zoom; + this.mouseY = (y - rect.top) / this.zoom + + this.zoomY + - this.destCanvas.height * 0.5 / this.zoom; + + if (isNaN(this.prevMouseX)) { + this.prevMouseX = this.mouseX; + } + if (isNaN(this.prevMouseY)) { + this.prevMosueY = this.mouseY; + } + + this.slowX = this.slowX * 0.8 + this.mouseX * 0.2; + this.slowY = this.slowY * 0.8 + this.mouseY * 0.2; + var now = new Date().getTime(); + if (this.stab) { + var pause = this.stab[3]; + if (pause) { + // ポーズ中 + if (now > pause) { + this.stab = [this.slowX, this.slowY, now]; + } + + } else { + // ポーズされていないとき + var prev = this.stab[2]; + if (now - prev > 150) { // 150ms以上止まっていたらポーズをオンにする + this.stab[3] = now + 200 // 200msペンの位置を固定 + + } else { + this.stab = [this.slowX, this.slowY, now]; + } + } + } else { + this.stab = [this.slowX, this.slowY, now]; + } + + this.rawMouseX = x; + this.rawMouseY = y; + this.clipMouseX = Math.max(Math.min(this.canvasWidth, this.mouseX), 0); + this.clipMouseY = Math.max(Math.min(this.canvasHeight, this.mouseY), 0); +}; + +Neo.Painter.prototype._beforeUnloadHandler = function(e) { + // quick save +}; + +Neo.Painter.prototype.getStabilized = function() { + return this.stab; +}; + +/* +------------------------------------------------------------------------- + Undo +------------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.undo = function() { + var undoItem = this._undoMgr.popUndo(); + if (undoItem) { + this._pushRedo(); + this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y); + this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y); + this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height); + } +}; + +Neo.Painter.prototype.redo = function() { + var undoItem = this._undoMgr.popRedo(); + if (undoItem) { + this._pushUndo(0,0,this.canvasWidth, this.canvasHeight, true); + this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y); + this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y); + this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height); + } +}; + +Neo.Painter.prototype.hasUndo = function() { + return true; +}; + +Neo.Painter.prototype._pushUndo = function(x, y, w, h, holdRedo) { + x = (x == undefined) ? 0 : x; + y = (y == undefined) ? 0 : y; + w = (w == undefined) ? this.canvasWidth : w; + h = (h == undefined) ? this.canvasHeight : h; + var undoItem = new Neo.UndoItem(); + undoItem.x = 0; + undoItem.y = 0; + undoItem.width = w; + undoItem.height = h; + undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h), + this.canvasCtx[1].getImageData(x, y, w, h)]; + this._undoMgr.pushUndo(undoItem, holdRedo); +}; + +Neo.Painter.prototype._pushRedo = function(x, y, w, h) { + x = (x == undefined) ? 0 : x; + y = (y == undefined) ? 0 : y; + w = (w == undefined) ? this.canvasWidth : w; + h = (h == undefined) ? this.canvasHeight : h; + var undoItem = new Neo.UndoItem(); + undoItem.x = 0; + undoItem.y = 0; + undoItem.width = w; + undoItem.height = h; + undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h), + this.canvasCtx[1].getImageData(x, y, w, h)]; + this._undoMgr.pushRedo(undoItem); +}; + + +/* +------------------------------------------------------------------------- + Data Cache for Undo / Redo +------------------------------------------------------------------------- +*/ + +Neo.UndoManager = function(_maxStep){ + this._maxStep = _maxStep; + this._undoItems = []; + this._redoItems = []; +} +Neo.UndoManager.prototype._maxStep; +Neo.UndoManager.prototype._redoItems; +Neo.UndoManager.prototype._undoItems; + +//アクションをしてUndo情報を更新 +Neo.UndoManager.prototype.pushUndo = function(undoItem, holdRedo) { + this._undoItems.push(undoItem); + if (this._undoItems.length > this._maxStep) { + this._undoItems.shift(); + } + + if (!holdRedo == true) { + this._redoItems = []; + } +}; + +Neo.UndoManager.prototype.popUndo = function() { + return this._undoItems.pop(); +} + +Neo.UndoManager.prototype.pushRedo = function(undoItem) { + this._redoItems.push(undoItem); +} + +Neo.UndoManager.prototype.popRedo = function() { + return this._redoItems.pop(); +} + + +Neo.UndoItem = function() {} +Neo.UndoItem.prototype.data; +Neo.UndoItem.prototype.x; +Neo.UndoItem.prototype.y; +Neo.UndoItem.prototype.width; +Neo.UndoItem.prototype.height; + +/* +------------------------------------------------------------------------- + Zoom Controller +------------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.setZoom = function(value) { + this.zoom = value; + + var container = document.getElementById("container"); + var width = this.canvasWidth * this.zoom; + var height = this.canvasHeight * this.zoom; + if (width > container.clientWidth - 100) width = container.clientWidth - 100; + if (height > container.clientHeight - 130) height = container.clientHeight - 130; + this.destWidth = width; + this.destHeight = height; + + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight, false); + this.setZoomPosition(this.zoomX, this.zoomY); +}; + +Neo.Painter.prototype.setZoomPosition = function(x, y) { + var minx = (this.destCanvas.width / this.zoom) * 0.5; + var maxx = this.canvasWidth - minx; + var miny = (this.destCanvas.height / this.zoom) * 0.5; + var maxy = this.canvasHeight - miny; + + + x = Math.round(Math.max(Math.min(maxx,x),minx)); + y = Math.round(Math.max(Math.min(maxy,y),miny)); + + this.zoomX = x; + this.zoomY = y; + this.updateDestCanvas(0,0,this.canvasWidth,this.canvasHeight,false); + + this.scrollBarX = (maxx == minx) ? 0 : (x - minx) / (maxx - minx); + this.scrollBarY = (maxy == miny) ? 0 : (y - miny) / (maxy - miny); + this.scrollWidth = maxx - minx; + this.scrollHeight = maxy - miny; + + if (Neo.scrollH) Neo.scrollH.update(this); + if (Neo.scrollV) Neo.scrollV.update(this); + + this.hideInputText(); +}; + + +/* +------------------------------------------------------------------------- + Drawing Helper +------------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.submit = function(board) { + var thumbnail = null; + var thumbnail2 = null; + + if (this.useThumbnail()) { + thumbnail = this.getThumbnail(Neo.config.thumbnail_type || "png"); + if (Neo.config.thumbnail_type2) { + thumbnail2 = this.getThumbnail(Neo.config.thumbnail_type2); + } + } + Neo.submit(board, this.getPNG(), thumbnail2, thumbnail); +}; + +Neo.Painter.prototype.useThumbnail = function() { + var thumbnailWidth = this.getThumbnailWidth(); + var thumbnailHeight = this.getThumbnailHeight(); + if (thumbnailWidth && thumbnailHeight) { + if (thumbnailWidth < this.canvasWidth || + thumbnailHeight < this.canvasHeight) { + return true; + } + } + return false; +}; + +Neo.Painter.prototype.dataURLtoBlob = function(dataURL) { + var byteString; + if (dataURL.split(',')[0].indexOf('base64') >= 0) { + byteString = atob(dataURL.split(',')[1]); + } else { + byteString = unescape(dataURL.split(',')[1]); + } + + // write the bytes of the string to a typed array + var ia = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + return new Blob([ia], {type:'image/png'}); +}; + +Neo.Painter.prototype.getImage = function(imageWidth, imageHeight) { + var width = this.canvasWidth; + var height = this.canvasHeight; + imageWidth = imageWidth || width; + imageHeight = imageHeight || height; + + var pngCanvas = document.createElement("canvas"); + pngCanvas.width = imageWidth; + pngCanvas.height = imageHeight; + var pngCanvasCtx = pngCanvas.getContext("2d"); + pngCanvasCtx.fillStyle = "#ffffff"; + pngCanvasCtx.fillRect(0, 0, imageWidth, imageHeight); + + if (this.visible[0]) { + pngCanvasCtx.drawImage(this.canvas[0], + 0, 0, width, height, + 0, 0, imageWidth, imageHeight); + } + if (this.visible[1]) { + pngCanvasCtx.drawImage(this.canvas[1], + 0, 0, width, height, + 0, 0, imageWidth, imageHeight); + } + return pngCanvas; +}; + +Neo.Painter.prototype.getPNG = function() { + var image = this.getImage(); + var dataURL = image.toDataURL('image/png'); + return this.dataURLtoBlob(dataURL); +}; + +Neo.Painter.prototype.getThumbnail = function(type) { + if (type != "animation") { + var thumbnailWidth = this.getThumbnailWidth(); + var thumbnailHeight = this.getThumbnailHeight(); + if (thumbnailWidth || thumbnailHeight) { + var width = this.canvasWidth; + var height = this.canvasHeight; + if (thumbnailWidth == 0) { + thumbnailWidth = thumbnailHeight * width / height; + } + if (thumbnailHeight == 0) { + thumbnailHeight = thumbnailWidth * height / width; + } + } else { + thumbnailWidth = thumbnailHeight = null; + } + + console.log("get thumbnail", thumbnailWidth, thumbnailHeight); + + var image = this.getImage(thumbnailWidth, thumbnailHeight); + var dataURL = image.toDataURL('image/' + type); + return this.dataURLtoBlob(dataURL); + + } else { + return new Blob([]); //animationには対応していないのでダミーデータを返す + } +}; + +Neo.Painter.prototype.getThumbnailWidth = function() { + var width = Neo.config.thumbnail_width; + if (width) { + if (width.match(/%$/)) { + return Math.floor(this.canvasWidth * (parseInt(width) / 100.0)); + } else { + return parseInt(width); + } + } + return 0; +}; + +Neo.Painter.prototype.getThumbnailHeight = function() { + var height = Neo.config.thumbnail_height; + if (height) { + if (height.match(/%$/)) { + return Math.floor(this.canvasHeight * (parseInt(height) / 100.0)); + } else { + return parseInt(height); + } + } + return 0; +}; + +Neo.Painter.prototype.clearCanvas = function(doConfirm) { + if (!doConfirm || confirm("Borrar todo")) { + //Register undo first; + this._pushUndo(); + + this.canvasCtx[0].clearRect(0, 0, this.canvasWidth, this.canvasHeight); + this.canvasCtx[1].clearRect(0, 0, this.canvasWidth, this.canvasHeight); + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight); + } +}; + +Neo.Painter.prototype.updateDestCanvas = function(x, y, width, height, useTemp) { + var canvasWidth = this.canvasWidth; + var canvasHeight = this.canvasHeight; + var updateAll = false; + if (x == 0 && y == 0 && width == canvasWidth && height == canvasHeight) { + updateAll = true; + }; + + if (x + width > this.canvasWidth) width = this.canvasWidth - x; + if (y + height > this.canvasHeight) height = this.canvasHeight - y; + if (x < 0) x = 0; + if (y < 0) y = 0; + if (width <= 0 || height <= 0) return; + + var ctx = this.destCanvasCtx; + ctx.save(); + ctx.fillStyle = "#ffffff"; + + if (updateAll) { + ctx.fillRect(0, 0, this.destCanvas.width, this.destCanvas.height); + } else { + //カーソルの描画ゴミが残るのをごまかすため + if (x + width == this.canvasWidth) width++; + if (y + height == this.canvasHeight) height++; + } + + ctx.translate(this.destCanvas.width*.5, this.destCanvas.height*.5); + ctx.scale(this.zoom, this.zoom); + ctx.translate(-this.zoomX, -this.zoomY); + ctx.globalAlpha = 1.0; + ctx.msImageSmoothingEnabled = 0; + + if (!updateAll) { + ctx.fillRect(x, y, width, height); + } + + if (this.visible[0]) { + ctx.drawImage(this.canvas[0], + x, y, width, height, + x, y, width, height); + } + if (this.visible[1]) { + ctx.drawImage(this.canvas[1], + x, y, width, height, + x, y, width, height); + } + if (useTemp) { + ctx.globalAlpha = 1.0; //this.alpha; + ctx.drawImage(this.tempCanvas, + x, y, width, height, + x + this.tempX, y + this.tempY, width, height); + } + ctx.restore(); +}; + +Neo.Painter.prototype.getBound = function(x0, y0, x1, y1, r) { + var left = Math.floor((x0 < x1) ? x0 : x1); + var top = Math.floor((y0 < y1) ? y0 : y1); + var width = Math.ceil(Math.abs(x0 - x1)); + var height = Math.ceil(Math.abs(y0 - y1)); + r = Math.ceil(r + 1); + + if (!r) { + width += 1; + height += 1; + + } else { + left -= r; + top -= r; + width += r * 2; + height += r * 2; + } + return [left, top, width, height]; +}; + +Neo.Painter.prototype.getColor = function(c) { + if (!c) c = this.foregroundColor; + var r = parseInt(c.substr(1, 2), 16); + var g = parseInt(c.substr(3, 2), 16); + var b = parseInt(c.substr(5, 2), 16); + var a = Math.floor(this.alpha * 255); + return a <<24 | b<<16 | g<<8 | r; +}; + +Neo.Painter.prototype.getColorString = function(c) { + var rgb = ("000000" + (c & 0xffffff).toString(16)).substr(-6); + return '#' + rgb; +}; + +Neo.Painter.prototype.setColor = function(c) { + if (typeof c != "string") c = this.getColorString(c); + this.foregroundColor = c; + + Neo.updateUI(); +}; + +Neo.Painter.prototype.getAlpha = function(type) { + var a1 = this.alpha; + + switch (type) { + case Neo.Painter.ALPHATYPE_PEN: + if (a1 > 0.5) { + a1 = 1.0/16 + (a1 - 0.5) * 30.0/16; + } else { + a1 = Math.sqrt(2 * a1) / 16.0; + } + a1 = Math.min(1, Math.max(0, a1)); + break; + + case Neo.Painter.ALPHATYPE_FILL: + a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042; + a1 = Math.min(1.0, Math.max(0, a1 * 10)); + break; + + case Neo.Painter.ALPHATYPE_BRUSH: + a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042; + a1 = Math.min(1.0, Math.max(0, a1)); + break; + } + + // アルファが小さい時は適当に点を抜いて見た目の濃度を合わせる + if (a1 < 1.0/255) { + this.aerr += a1; + a1 = 0; + while (this.aerr > 1.0/255) { + a1 = 1.0/255; + this.aerr -= 1.0/255; + } + } + return a1; +}; + +Neo.Painter.prototype.prepareDrawing = function () { + var r = parseInt(this.foregroundColor.substr(1, 2), 16); + var g = parseInt(this.foregroundColor.substr(3, 2), 16); + var b = parseInt(this.foregroundColor.substr(5, 2), 16); + var a = Math.floor(this.alpha * 255); + + var maskR = parseInt(this.maskColor.substr(1, 2), 16); + var maskG = parseInt(this.maskColor.substr(3, 2), 16); + var maskB = parseInt(this.maskColor.substr(5, 2), 16); + + this._currentColor = [r, g, b, a]; + this._currentMask = [maskR, maskG, maskB]; +}; + +Neo.Painter.prototype.isMasked = function (buf8, index) { + var r = this._currentMask[0]; + var g = this._currentMask[1]; + var b = this._currentMask[2]; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3]; + + if (a0 == 0) { + r0 = 0xff; + g0 = 0xff; + b0 = 0xff; + } + + var type = this.maskType; + + //TODO + //いろいろ試したのですが半透明で描画するときの加算・逆加算を再現する方法がわかりません。 + //とりあえず単純に無視しています。 + if (type == Neo.Painter.MASKTYPE_ADD || + type == Neo.Painter.MASKTYPE_SUB) { + if (this._currentColor[3] < 250) { + type = Neo.Painter.MASKTYPE_NONE; + } + } + + switch (type) { + case Neo.Painter.MASKTYPE_NONE: + return; + + case Neo.Painter.MASKTYPE_NORMAL: + return (r0 == r && + g0 == g && + b0 == b) ? true : false; + + case Neo.Painter.MASKTYPE_REVERSE: + return (r0 != r || + g0 != g || + b0 != b) ? true : false; + + case Neo.Painter.MASKTYPE_ADD: + if (a0 > 0) { + var sort = this.sortColor(r0, g0, b0); + for (var i = 0; i < 3; i++) { + var c = sort[i]; + if (buf8[index + c] < this._currentColor[c]) return true; + } + return false; + + } else { + return false; + } + + case Neo.Painter.MASKTYPE_SUB: + if (a0 > 0) { + var sort = this.sortColor(r0, g0, b0); + for (var i = 0; i < 3; i++) { + var c = sort[i]; + if (buf8[index + c] > this._currentColor[c]) return true; + } + return false; + } else { + return true; + } + } +}; + +Neo.Painter.prototype.setPoint = function(buf8, bufWidth, x0, y0, left, top, type) { + var x = x0 - left; + var y = y0 - top; + + switch (type) { + case Neo.Painter.LINETYPE_PEN: + this.setPenPoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_BRUSH: + this.setBrushPoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_TONE: + this.setTonePoint(buf8, bufWidth, x, y, x0, y0); + break; + + case Neo.Painter.LINETYPE_ERASER: + this.setEraserPoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_BLUR: + this.setBlurPoint(buf8, bufWidth, x, y, x0, y0); + break; + + case Neo.Painter.LINETYPE_DODGE: + this.setDodgePoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_BURN: + this.setBurnPoint(buf8, bufWidth, x, y); + break; + + default: + break; + } +}; + + +Neo.Painter.prototype.setPenPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_PEN); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + if (a > 0) { + var a1x = Math.max(a1, 1.0/255); + + var r = (r1 * a1x + r0 * a0 * (1 - a1x)) / a; + var g = (g1 * a1x + g0 * a0 * (1 - a1x)) / a; + var b = (b1 * a1x + b0 * a0 * (1 - a1x)) / a; + + r = (r1 > r0) ? Math.ceil(r) : Math.floor(r); + g = (g1 > g0) ? Math.ceil(g) : Math.floor(g); + b = (b1 > b0) ? Math.ceil(b) : Math.floor(b); + } + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setBrushPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + if (a > 0) { + var a1x = Math.max(a1, 1.0/255); + + var r = (r1 * a1x + r0 * a0) / (a0 + a1x); + var g = (g1 * a1x + g0 * a0) / (a0 + a1x); + var b = (b1 * a1x + b0 * a0) / (a0 + a1x); + + r = (r1 > r0) ? Math.ceil(r) : Math.floor(r); + g = (g1 > g0) ? Math.ceil(g) : Math.floor(g); + b = (b1 > b0) ? Math.ceil(b) : Math.floor(b); + } + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setTonePoint = function(buf8, width, x, y, x0, y0) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + if (r0%2) { x0++; y0++; } //なぜか模様がずれるので + + var shape = this._roundData[d]; + var shapeIndex = 0; + var index = (y * width + x) * 4; + + var r = this._currentColor[0]; + var g = this._currentColor[1]; + var b = this._currentColor[2]; + var a = this._currentColor[3]; + + var toneData = this.getToneData(a); + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + if (toneData[((y0+i)%4) + (((x0+j)%4) * 4)]) { + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = 255; + } + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setEraserPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var shape = this._roundData[d]; + var shapeIndex = 0; + var index = (y * width + x) * 4; + var a = Math.floor(this.alpha * 255); + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var k = (buf8[index + 3] / 255.0) * (1.0 - (a / 255.0)); + + buf8[index + 3] -= a / (d * (255.0 - a) / 255.0); + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setBlurPoint = function(buf8, width, x, y, x0, y0) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var shape = this._roundData[d]; + var shapeIndex = 0; + var height = buf8.length / (width * 4); + +// var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + var a1 = this.alpha / 12; + if (a1 == 0) return; + var blur = a1; + + var tmp = new Uint8ClampedArray(buf8.length); + for (var i = 0; i < buf8.length; i++) { + tmp[i] = buf8[i]; + } + + var left = x0 - x - r0; + var top = y0 - y - r0; + + var xstart = 0, xend = d; + var ystart = 0, yend = d; + if (xstart > left) xstart = -left; + if (ystart > top) ystart = -top; + if (xend > this.canvasWidth - left) xend = this.canvasWidth - left; + if (yend > this.canvasHeight - top) yend = this.canvasHeight - top; + + for (var j = ystart; j < yend; j++) { + var index = (j * width + xstart) * 4; + for (var i = xstart; i < xend; i++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var rgba = [0, 0, 0, 0, 0]; + + this.addBlur(tmp, index, 1.0 - blur*4, rgba); + if (i > xstart) this.addBlur(tmp, index - 4, blur, rgba); + if (i < xend - 1) this.addBlur(tmp, index + 4, blur, rgba); + if (j > ystart) this.addBlur(tmp, index - width*4, blur, rgba); + if (j < yend - 1) this.addBlur(tmp, index + width*4, blur, rgba); + + buf8[index + 0] = Math.round(rgba[0]); + buf8[index + 1] = Math.round(rgba[1]); + buf8[index + 2] = Math.round(rgba[2]); + buf8[index + 3] = Math.round((rgba[3] / rgba[4]) * 255.0); + } + index += 4; + } + } +}; + +Neo.Painter.prototype.setDodgePoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + if (a1 != 255.0) { + var r1 = r0 * 255 / (255 - a1); + var g1 = g0 * 255 / (255 - a1); + var b1 = b0 * 255 / (255 - a1); + } else { + var r1 = 255.0; + var g1 = 255.0; + var b1 = 255.0; + } + + var r = Math.ceil(r1); + var g = Math.ceil(g1); + var b = Math.ceil(b1); + var a = a0; + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setBurnPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + if (a1 != 255.0) { + var r1 = 255 - (255 - r0) * 255 / (255 - a1); + var g1 = 255 - (255 - g0) * 255 / (255 - a1); + var b1 = 255 - (255 - b0) * 255 / (255 - a1); + } else { + var r1 = 0; + var g1 = 0; + var b1 = 0; + } + + var r = Math.floor(r1); + var g = Math.floor(g1); + var b = Math.floor(b1); + var a = a0; + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +////////////////////////////////////////////////////////////////////// + +Neo.Painter.prototype.xorPixel = function(buf32, bufWidth, x, y, c) { + var index = y * bufWidth + x; + if (!c) c = 0xffffff; + buf32[index] ^= c; +}; + +Neo.Painter.prototype.getBezierPoint = function(t, x0, y0, x1, y1, x2, y2, x3, y3) { + var a0 = (1 - t) * (1 - t) * (1 - t); + var a1 = (1 - t) * (1 - t) * t * 3; + var a2 = (1 - t) * t * t * 3; + var a3 = t * t * t; + + var x = x0 * a0 + x1 * a1 + x2 * a2 + x3 * a3; + var y = y0 * a0 + y1 * a1 + y2 * a2 + y3 * a3; + return [x, y]; +}; + +var nmax = 1; + +Neo.Painter.prototype.drawBezier = function(ctx, x0, y0, x1, y1, x2, y2, x3, y3, type) { + var xmax = Math.max(x0, x1, x2, x3); + var xmin = Math.min(x0, x1, x2, x3); + var ymax = Math.max(y0, y1, y2, y3); + var ymin = Math.min(y0, y1, y2, y3); + var n = Math.ceil(((xmax - xmin) + (ymax - ymin)) * 2.5); + + if (n > nmax) { + n = (n < nmax * 2) ? n : nmax * 2; + nmax = n; + } + + for (var i = 0; i < n; i++) { + var t = i * 1.0 / n; + var p = this.getBezierPoint(t, x0, y0, x1, y1, x2, y2, x3, y3); + this.drawPoint(ctx, p[0], p[1], type); + } +}; + +Neo.Painter.prototype.prevLine = null; // 始点または終点が2度プロットされることがあるので +Neo.Painter.prototype.drawLine = function(ctx, x0, y0, x1, y1, type) { + x0 = Math.round(x0); + x1 = Math.round(x1); + y0 = Math.round(y0); + y1 = Math.round(y1); + var prev = [x0, y0, x1, y1]; + + var width = Math.abs(x1 - x0); + var height = Math.abs(y1 - y0); + var r = Math.ceil(this.lineWidth / 2); + + var left = ((x0 < x1) ? x0 : x1) - r; + var top = ((y0 < y1) ? y0 : y1) - r; + + var imageData = ctx.getImageData(left, top, width + r*2, height + r*2); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var dx = width, sx = x0 < x1 ? 1 : -1; + var dy = height, sy = y0 < y1 ? 1 : -1; + var err = (dx > dy ? dx : -dy) / 2; + this.aerr = 0; + + while (true) { + if (this.prevLine == null || + !((this.prevLine[0] == x0 && this.prevLine[1] == y0) || + (this.prevLine[2] == x0 && this.prevLine[3] == y0))) { + this.setPoint(buf8, imageData.width, x0, y0, left, top, type); + } + + if (x0 === x1 && y0 === y1) break; + var e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } + + imageData.data.set(buf8); + ctx.putImageData(imageData, left, top); + + this.prevLine = prev; +}; + +Neo.Painter.prototype.drawPoint = function(ctx, x, y, type) { + this.drawLine(ctx, x, y, x, y, type); +}; + +Neo.Painter.prototype.xorRect = function(buf32, bufWidth, x, y, width, height, c) { + var index = y * bufWidth + x; + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + buf32[index] ^= c; + index++; + } + index += width - bufWidth; + } +}; + +Neo.Painter.prototype.drawXORRect = function(ctx, x, y, width, height, isFill, c) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + if (width == 0 || height == 0) return; + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var index = 0; + if (!c) c = 0xffffff; + + if (isFill) { + this.xorRect(buf32, width, 0, 0, width, height, c); + + } else { + for (var i = 0; i < width; i++) { //top + buf32[index] = buf32[index] ^= c; + index++; + } + if (height > 1) { + index = width; + for (var i = 1; i < height; i++) { //left + buf32[index] = buf32[index] ^= c; + index += width; + } + if (width > 1) { + index = width * 2 - 1; + for (var i = 1; i < height - 1; i++) { //right + buf32[index] = buf32[index] ^= c; + index += width; + } + index = width * (height - 1) + 1; + for (var i = 1; i < width; i++) { // bottom + buf32[index] = buf32[index] ^= c; + index++; + } + } + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.drawXOREllipse = function(ctx, x, y, width, height, isFill, c) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + if (width == 0 || height == 0) return; + if (!c) c = 0xffffff; + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + + var a = width-1, b = height-1, b1 = b&1; /* values of diameter */ + var dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */ + var err = dx+dy+b1*a*a, e2; /* error of 1.step */ + + var x0 = x; + var y0 = y; + var x1 = x0+a; + var y1 = y0+b; + + if (x0 > x1) { x0 = x1; x1 += a; } + if (y0 > y1) y0 = y1; + y0 += Math.floor((b+1)/2); y1 = y0-b1; /* starting pixel */ + a *= 8*a; b1 = 8*b*b; + var ymin = y0 - 1; + + do { + if (isFill) { + if (ymin < y0) { + this.xorRect(buf32, width, x0-x, y0 - y, x1 - x0, 1, c); + if (y0 != y1) { + this.xorRect(buf32, width, x0-x, y1 - y, x1 - x0, 1, c); + } + ymin = y0; + } + } else { + this.xorPixel(buf32, width, x1-x, y0-y, c); + if (x0 != x1) { + this.xorPixel(buf32, width, x0-x, y0-y, c); + } + if (y0 != y1) { + this.xorPixel(buf32, width, x0-x, y1-y, c); + if (x0 != x1) { + this.xorPixel(buf32, width, x1-x, y1-y, c); + } + } + } + e2 = 2*err; + if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ + if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */ + } while (x0 <= x1); + + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.drawXORLine = function(ctx, x0, y0, x1, y1, c) { + x0 = Math.round(x0); + x1 = Math.round(x1); + y0 = Math.round(y0); + y1 = Math.round(y1); + + var width = Math.abs(x1 - x0); + var height = Math.abs(y1 - y0); + + var left = ((x0 < x1) ? x0 : x1); + var top = ((y0 < y1) ? y0 : y1); +// console.log("left:"+left+" top:"+top+" width:"+width+" height:"+height); + + var imageData = ctx.getImageData(left, top, width + 1, height + 1); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var dx = width, sx = x0 < x1 ? 1 : -1; + var dy = height, sy = y0 < y1 ? 1 : -1; + var err = (dx > dy ? dx : -dy) / 2; + + while (true) { + if (this.prevLine == null || + !((this.prevLine[0] == x0 && this.prevLine[1] == y0) || + (this.prevLine[2] == x0 && this.prevLine[3] == y0))) { + + this.xorPixel(buf32, imageData.width, x0 - left, y0 - top, c); + } + + if (x0 === x1 && y0 === y1) break; + var e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } + + imageData.data.set(buf8); + ctx.putImageData(imageData, left, top); +}; + + +Neo.Painter.prototype.eraseRect = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var index = 0; + + var a = 1.0 - this.alpha; + if (a != 0) { + a = Math.ceil(2.0 / a); + } else { + a = 255; + } + + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + if (!this.isMasked(buf8, index)) { + buf8[index + 3] -= a; + } + index += 4; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.flipH = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var half = Math.floor(width / 2); + for (var j = 0; j < height; j++) { + var index = j * width; + var index2 = index + (width - 1); + for (var i = 0; i < half; i++) { + var value = buf32[index + i]; + buf32[index + i] = buf32[index2 -i]; + buf32[index2 - i] = value; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.flipV = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var half = Math.floor(height / 2); + for (var j = 0; j < half; j++) { + var index = j * width; + var index2 = (height - 1 - j) * width; + for (var i = 0; i < width; i++) { + var value = buf32[index + i]; + buf32[index + i] = buf32[index2 + i]; + buf32[index2 + i] = value; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.merge = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = []; + var buf32 = []; + var buf8 = []; + for (var i = 0; i < 2; i++) { + imageData[i] = this.canvasCtx[i].getImageData(x, y, width, height); + buf32[i] = new Uint32Array(imageData[i].data.buffer); + buf8[i] = new Uint8ClampedArray(imageData[i].data.buffer); + } + + var dst = this.current; + var src = (dst == 1) ? 0 : 1; + var size = width * height; + var index = 0; + for (var i = 0; i < size; i++) { + var r0 = buf8[0][index + 0]; + var g0 = buf8[0][index + 1]; + var b0 = buf8[0][index + 2]; + var a0 = buf8[0][index + 3] / 255.0; + var r1 = buf8[1][index + 0]; + var g1 = buf8[1][index + 1]; + var b1 = buf8[1][index + 2]; + var a1 = buf8[1][index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + if (a > 0) { + var r = Math.floor((r1 * a1 + r0 * a0 * (1 - a1)) / a + 0.5); + var g = Math.floor((g1 * a1 + g0 * a0 * (1 - a1)) / a + 0.5); + var b = Math.floor((b1 * a1 + b0 * a0 * (1 - a1)) / a + 0.5); + } + buf8[src][index + 0] = 0; + buf8[src][index + 1] = 0; + buf8[src][index + 2] = 0; + buf8[src][index + 3] = 0; + buf8[dst][index + 0] = r; + buf8[dst][index + 1] = g; + buf8[dst][index + 2] = b; + buf8[dst][index + 3] = Math.floor(a * 255 + 0.5); + index += 4; + } + + for (var i = 0; i < 2; i++) { + imageData[i].data.set(buf8[i]); + this.canvasCtx[i].putImageData(imageData[i], x, y); + } +}; + +Neo.Painter.prototype.blurRect = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var tmp = new Uint8ClampedArray(buf8.length); + for (var i = 0; i < buf8.length; i++) tmp[i] = buf8[i]; + + var index = 0; + var a1 = this.alpha / 12; + var blur = a1; + + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + var rgba = [0, 0, 0, 0, 0]; + + this.addBlur(tmp, index, 1.0 - blur*4, rgba); + + if (i > 0) this.addBlur(tmp, index - 4, blur, rgba); + if (i < width - 1) this.addBlur(tmp, index + 4, blur, rgba); + if (j > 0) this.addBlur(tmp, index - width*4, blur, rgba); + if (j < height - 1) this.addBlur(tmp, index + width*4, blur, rgba); + + var w = rgba[4]; + buf8[index + 0] = Math.round(rgba[0]); + buf8[index + 1] = Math.round(rgba[1]); + buf8[index + 2] = Math.round(rgba[2]); + buf8[index + 3] = Math.ceil((rgba[3] / w) * 255.0); + + index += 4; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.addBlur = function(buffer, index, a, rgba) { + var r0 = rgba[0]; + var g0 = rgba[1]; + var b0 = rgba[2]; + var a0 = rgba[3]; + var r1 = buffer[index + 0]; + var g1 = buffer[index + 1]; + var b1 = buffer[index + 2]; + var a1 = (buffer[index + 3] / 255.0) * a; + rgba[4] += a; + + var a = a0 + a1; + if (a > 0) { + rgba[0] = (r1 * a1 + r0 * a0) / (a0 + a1); + rgba[1] = (g1 * a1 + g0 * a0) / (a0 + a1); + rgba[2] = (b1 * a1 + b0 * a0) / (a0 + a1); + rgba[3] = a; + } +}; + +Neo.Painter.prototype.pickColor = function(x, y) { + var r = 0xff, g = 0xff, b = 0xff, a; + + x = Math.floor(x); + y = Math.floor(y); + if (x >= 0 && x < this.canvasWidth && + y >= 0 && y < this.canvasHeight) { + + for (var i = 0; i < 2; i++) { + if (this.visible[i]) { + var ctx = this.canvasCtx[i]; + var imageData = ctx.getImageData(x, y, 1, 1); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var a = buf8[3] / 255.0; + r = r * (1.0 - a) + buf8[2] * a; + g = g * (1.0 - a) + buf8[1] * a; + b = b * (1.0 - a) + buf8[0] * a; + } + } + r = Math.max(Math.min(Math.round(r), 255), 0); + g = Math.max(Math.min(Math.round(g), 255), 0); + b = Math.max(Math.min(Math.round(b), 255), 0); + var result = r | g<<8 | b<<16; + } + this.setColor(result); + + + if (this.current > 0) { + if (a == 0 && (result == 0xffffff || this.getEmulationMode() < 2.16)) { + this.setToolByType(Neo.eraserTip.tools[Neo.eraserTip.mode]); + + } else { + if (Neo.eraserTip.selected) { + this.setToolByType(Neo.penTip.tools[Neo.penTip.mode]); + } + } + } +}; + +Neo.Painter.prototype.fillHorizontalLine = function(buf32, x0, x1, y) { + var index = y * this.canvasWidth + x0; + var fillColor = this.getColor(); + for (var x = x0; x <= x1; x++) { + buf32[index++] = fillColor; + } +}; + +Neo.Painter.prototype.scanLine = function(x0, x1, y, baseColor, buf32, stack) { + var width = this.canvasWidth; + + while (x0 <= x1) { + for (; x0 <= x1; x0++) { + if (buf32[y * width + x0] == baseColor) break; + } + if (x1 < x0) break; + + for (; x0 <= x1; x0++) { + if (buf32[y * width + x0] != baseColor) break; + } + stack.push({x:x0 - 1, y: y}) + } +}; + +Neo.Painter.prototype.fill = function(x, y, ctx) { + // http://sandbox.serendip.ws/javascript_canvas_scanline_seedfill.html + x = Math.round(x); + y = Math.round(y); + + var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var width = imageData.width; + var stack = [{x: x, y: y}]; + + var baseColor = buf32[y * width + x]; + var fillColor = this.getColor(); + + if ((baseColor & 0xffffff00) == 0 || + (baseColor & 0xffffff) != (fillColor & 0xffffff)) { + while (stack.length > 0) { + var point = stack.pop(); + var x0 = point.x; + var x1 = point.x; + var y = point.y; + + if (buf32[y * width + x] == fillColor) + break; + + for (; 0 < x0; x0--) { + if (buf32[y * width + (x0 - 1)] != baseColor) break; + } + for (; x1 < this.canvasHeight - 1; x1++) { + if (buf32[y * width + (x1 + 1)] != baseColor) break; + } + this.fillHorizontalLine(buf32, x0, x1, y); + + if (y + 1 < this.canvasHeight) { + this.scanLine(x0, x1, y + 1, baseColor, buf32, stack); + } + if (y - 1 >= 0) { + this.scanLine(x0, x1, y - 1, baseColor, buf32, stack); + } + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype.copy = function(x, y, width, height) { + this.tempX = 0; + this.tempY = 0; + this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + + var imageData = this.canvasCtx[this.current].getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + this.temp = new Uint32Array(buf32.length); + for (var i = 0; i < buf32.length; i++) { + this.temp[i] = buf32[i]; + } + + //tempCanvasに乗せる画像を作る + imageData = this.tempCanvasCtx.getImageData(x, y, width, height); + buf32 = new Uint32Array(imageData.data.buffer); + buf8 = new Uint8ClampedArray(imageData.data.buffer); + for (var i = 0; i < buf32.length; i++) { + if (this.temp[i] >> 24) { + buf32[i] = this.temp[i] | 0xff000000; + } else { + buf32[i] = 0xffffffff; + } + } + imageData.data.set(buf8); + this.tempCanvasCtx.putImageData(imageData, x, y); +}; + + +Neo.Painter.prototype.paste = function(x, y, width, height) { + var ctx = this.canvasCtx[this.current]; +// console.log(this.tempX, this.tempY); + + var imageData = ctx.getImageData(x + this.tempX, y + this.tempY, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + for (var i = 0; i < buf32.length; i++) { + buf32[i] = this.temp[i]; + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x + this.tempX, y + this.tempY); + + this.temp = null; + this.tempX = 0; + this.tempY = 0; + this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype.turn = function(x, y, width, height) { + var ctx = this.canvasCtx[this.current]; + + // 傾けツールのバグを再現するため一番上のラインで対象領域を埋める + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var temp = new Uint32Array(buf32.length); + + var index = 0; + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + temp[index] = buf32[index]; + if (index >= width) { + buf32[index] = buf32[index % width]; + } + index++; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); + + // 90度回転させて貼り付け + imageData = ctx.getImageData(x, y, height, width); + buf32 = new Uint32Array(imageData.data.buffer); + buf8 = new Uint8ClampedArray(imageData.data.buffer); + + index = 0; + for (var j = height - 1; j >= 0; j--) { + for (var i = 0; i < width; i++) { + buf32[i * height + j] = temp[index++]; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.doFill = function(ctx, x, y, width, height, maskFunc) { + if (Math.round(x) != x) console.log("*"); + if (Math.round(width) != width) console.log("*"); + if (Math.round(height) != height) console.log("*"); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var index = 0; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + var a1 = this.getAlpha(Neo.ALPHATYPE_FILL); + + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + if (maskFunc && maskFunc.call(this, i, j, width, height)) { + //なぜか加算逆加算は適用されない + if (this.maskType >= Neo.Painter.MASKTYPE_ADD || + !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + + if (a > 0) { + var a1x = a1; + var ax = 1 + a0 * (1 - a1x); + + var r = (r1 + r0 * a0 * (1 - a1x)) / ax; + var g = (g1 + g0 * a0 * (1 - a1x)) / ax; + var b = (b1 + b0 * a0 * (1 - a1x)) / ax + + r = (r1 > r0) ? Math.ceil(r) : Math.floor(r); + g = (g1 > g0) ? Math.ceil(g) : Math.floor(g); + b = (b1 > b0) ? Math.ceil(b) : Math.floor(b); + } + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + } + } + index += 4; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.rectFillMask = function(x, y, width, height) { + return true; +}; + +Neo.Painter.prototype.rectMask = function(x, y, width, height) { + var d = this.lineWidth; + return (x < d || x > width - 1 - d || + y < d || y > height - 1 - d) ? true : false; +}; + +Neo.Painter.prototype.ellipseFillMask = function(x, y, width, height) { + var cx = (width - 1) / 2.0; + var cy = (height - 1) / 2.0; + x = (x - cx) / (cx + 1); + y = (y - cy) / (cy + 1); + + return ((x * x) + (y * y) < 1) ? true : false; +} + +Neo.Painter.prototype.ellipseMask = function(x, y, width, height) { + var d = this.lineWidth; + var cx = (width - 1) / 2.0; + var cy = (height - 1) / 2.0; + + if (cx <= d || cy <= d) return this.ellipseFillMask(x, y, width, height); + + var x2 = (x - cx) / (cx - d + 1); + var y2 = (y - cy) / (cy - d + 1); + + x = (x - cx) / (cx + 1); + y = (y - cy) / (cy + 1); + + if ((x * x) + (y * y) < 1) { + if ((x2 * x2) + (y2 * y2) >= 1) { + return true; + } + } + return false; +} + +/* +----------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.getDestCanvasPosition = function(mx, my, isClip, isCenter) { + var mx = Math.floor(mx); //Math.round(mx); + var my = Math.floor(my); //Math.round(my); + if (isCenter) { + mx += 0.499; + my += 0.499; + } + var x = (mx - this.zoomX + this.destCanvas.width * 0.5 / this.zoom) * this.zoom; + var y = (my - this.zoomY + this.destCanvas.height * 0.5 / this.zoom) * this.zoom; + + if (isClip) { + x = Math.max(Math.min(x, this.destCanvas.width), 0); + y = Math.max(Math.min(y, this.destCanvas.height), 0); + } + return {x:x, y:y}; +}; + +Neo.Painter.prototype.isWidget = function(element) { + while (1) { + if (element == null || + element.id == "canvas" || + element.id == "container") break; + + if (element.id == "tools" || + element.className == "buttonOn" || + element.className == "buttonOff" || + element.className == "inputText") { + return true; + } + element = element.parentNode; + } + return false; +}; + + +Neo.Painter.prototype.loadImage = function (filename) { + console.log("loadImage " + filename); + var img = new Image(); + img.src = filename; + img.onload = function() { + var oe = Neo.painter; + oe.canvasCtx[0].drawImage(img, 0, 0); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight); + }; +} + +Neo.Painter.prototype.loadSession = function (filename) { + if (sessionStorage) { + var img0 = new Image(); + img0.src = sessionStorage.getItem('layer0'); + img0.onload = function() { + var img1 = new Image(); + img1.src = sessionStorage.getItem('layer1'); + img1.onload = function() { + var oe = Neo.painter; + oe.canvasCtx[0].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.canvasCtx[1].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.canvasCtx[0].drawImage(img0, 0, 0); + oe.canvasCtx[1].drawImage(img1, 0, 0); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight); + } + } + } +}; + +Neo.Painter.prototype.saveSession = function() { + if (sessionStorage) { + sessionStorage.setItem('timestamp', +(new Date())); + sessionStorage.setItem('layer0', this.canvas[0].toDataURL('image/png')); + sessionStorage.setItem('layer1', this.canvas[1].toDataURL('image/png')); + } +}; + +Neo.Painter.prototype.clearSession = function() { + if (sessionStorage) { + sessionStorage.removeItem('timestamp'); + sessionStorage.removeItem('layer0'); + sessionStorage.removeItem('layer1'); + } +}; + +Neo.Painter.prototype.sortColor = function(r0, g0, b0) { + var min = (r0 < g0) ? ((r0 < b0) ? 0 : 2) : ((g0 < b0) ? 1 : 2); + var max = (r0 > g0) ? ((r0 > b0) ? 0 : 2) : ((g0 > b0) ? 1 : 2); + var mid = (min + max == 1) ? 2 : ((min + max == 2) ? 1 : 0); + return [min, mid, max]; +}; + +Neo.Painter.prototype.doText = function(x, y, string, fontSize) { + //テキスト描画 + //描画位置がずれるので適当に調整 + var offset = parseInt(fontSize, 10); +// y -= Math.round((5.0 + offset/8) / this.zoom); +// x += Math.round(2.0 / this.zoom); + + var ctx = this.tempCanvasCtx; + ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + ctx.save(); + ctx.translate(x, y); +// ctx.scale(1/this.zoom, 1/this.zoom); + + ctx.font = fontSize + " Arial"; + ctx.fillStyle = 0; + ctx.fillText(string, 0, 0); + ctx.restore(); + + // 適当に二値化 + var c = this.getColor(); + var r = c & 0xff; + var g = (c & 0xff00) >> 8; + var b = (c & 0xff0000) >> 16; + var a = Math.round(this.alpha * 255.0); + + var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var length = this.canvasWidth * this.canvasHeight; + var index = 0; + for (var i = 0; i < length; i++) { + if (buf8[index + 3] >= 0x60) { + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } else { + buf8[index + 0] = 0; + buf8[index + 1] = 0; + buf8[index + 2] = 0; + buf8[index + 3] = 0; + } + index += 4; + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + + //キャンバスに貼り付け + ctx = this.canvasCtx[this.current]; + ctx.globalAlpha = 1.0; + ctx.drawImage(this.tempCanvas, + 0, 0, this.canvasWidth, this.canvasHeight, + 0, 0, this.canvasWidth, this.canvasHeight); + + this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype.isUIPaused = function() { + if (this.drawType == Neo.Painter.DRAWTYPE_BEZIER) { + if (this.tool.step && this.tool.step > 0) { + return true; + } + } + return false; +}; + +Neo.Painter.prototype.getEmulationMode = function() { + return parseFloat(Neo.config.neo_emulation_mode || 2.22) +}; + +'use strict'; + +Neo.ToolBase = function() {}; + +Neo.ToolBase.prototype.startX; +Neo.ToolBase.prototype.startY; +Neo.ToolBase.prototype.init = function(oe) {} +Neo.ToolBase.prototype.kill = function(oe) {} +Neo.ToolBase.prototype.lineType = Neo.Painter.LINETYPE_NONE; + +Neo.ToolBase.prototype.downHandler = function(oe) { + this.startX = oe.mouseX; + this.startY = oe.mouseY; +}; + +Neo.ToolBase.prototype.upHandler = function(oe) { +}; + +Neo.ToolBase.prototype.moveHandler = function(oe) { +}; + +Neo.ToolBase.prototype.transformForZoom = function(oe) { + var ctx = oe.destCanvasCtx; + ctx.translate(oe.canvasWidth * 0.5, oe.canvasHeight * 0.5); + ctx.scale(oe.zoom, oe.zoom); + ctx.translate(-oe.zoomX, -oe.zoomY); +}; + +Neo.ToolBase.prototype.getType = function() { + return this.type; +}; + +Neo.ToolBase.prototype.getToolButton = function() { + switch (this.type) { + case Neo.Painter.TOOLTYPE_PEN: + case Neo.Painter.TOOLTYPE_BRUSH: + case Neo.Painter.TOOLTYPE_TEXT: + return Neo.penTip; + + case Neo.Painter.TOOLTYPE_TONE: + case Neo.Painter.TOOLTYPE_BLUR: + case Neo.Painter.TOOLTYPE_DODGE: + case Neo.Painter.TOOLTYPE_BURN: + return Neo.pen2Tip; + + case Neo.Painter.TOOLTYPE_RECT: + case Neo.Painter.TOOLTYPE_RECTFILL: + case Neo.Painter.TOOLTYPE_ELLIPSE: + case Neo.Painter.TOOLTYPE_ELLIPSEFILL: + return Neo.effectTip; + + case Neo.Painter.TOOLTYPE_COPY: + case Neo.Painter.TOOLTYPE_MERGE: + case Neo.Painter.TOOLTYPE_BLURRECT: + case Neo.Painter.TOOLTYPE_FLIP_H: + case Neo.Painter.TOOLTYPE_FLIP_V: + case Neo.Painter.TOOLTYPE_TURN: + return Neo.effect2Tip; + + case Neo.Painter.TOOLTYPE_ERASER: + case Neo.Painter.TOOLTYPE_ERASEALL: + case Neo.Painter.TOOLTYPE_ERASERECT: + return Neo.eraserTip; + + case Neo.Painter.TOOLTYPE_FILL: + return Neo.fillButton; + } + return null; +}; + +Neo.ToolBase.prototype.getReserve = function() { + switch (this.type) { + case Neo.Painter.TOOLTYPE_ERASER: + return Neo.reserveEraser; + + case Neo.Painter.TOOLTYPE_PEN: + case Neo.Painter.TOOLTYPE_BRUSH: + case Neo.Painter.TOOLTYPE_TONE: + case Neo.Painter.TOOLTYPE_ERASERECT: + case Neo.Painter.TOOLTYPE_ERASEALL: + case Neo.Painter.TOOLTYPE_COPY: + case Neo.Painter.TOOLTYPE_MERGE: + case Neo.Painter.TOOLTYPE_FIP_H: + case Neo.Painter.TOOLTYPE_FIP_V: + + case Neo.Painter.TOOLTYPE_DODGE: + case Neo.Painter.TOOLTYPE_BURN: + case Neo.Painter.TOOLTYPE_BLUR: + case Neo.Painter.TOOLTYPE_BLURRECT: + + case Neo.Painter.TOOLTYPE_TEXT: + case Neo.Painter.TOOLTYPE_TURN: + case Neo.Painter.TOOLTYPE_RECT: + case Neo.Painter.TOOLTYPE_RECTFILL: + case Neo.Painter.TOOLTYPE_ELLIPSE: + case Neo.Painter.TOOLTYPE_ELLIPSEFILL: + return Neo.reservePen; + + } + return null; +}; + +Neo.ToolBase.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.updateUI(); + } +}; + +Neo.ToolBase.prototype.saveStates = function() { + var reserve = this.getReserve(); + if (reserve) { + reserve.size = Neo.painter.lineWidth; + } +}; + +/* +------------------------------------------------------------------------- + DrawToolBase(描画ツールのベースクラス) +------------------------------------------------------------------------- +*/ + +Neo.DrawToolBase = function() {}; +Neo.DrawToolBase.prototype = new Neo.ToolBase(); +Neo.DrawToolBase.prototype.isUpMove = false; +Neo.DrawToolBase.prototype.step = 0; + +Neo.DrawToolBase.prototype.init = function() { + this.step = 0; + this.isUpMove = true; +}; + +Neo.DrawToolBase.prototype.downHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandDownHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineDownHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierDownHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.upHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandUpHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineUpHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierUpHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.moveHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierMoveHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.upMoveHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandUpMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineUpMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierUpMoveHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.keyDownHandler = function(e) { + switch (Neo.painter.drawType) { + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierKeyDownHandler(e); break; + } +}; + +Neo.DrawToolBase.prototype.rollOverHandler= function(oe) {}; +Neo.DrawToolBase.prototype.rollOutHandler= function(oe) { + if (!oe.isMouseDown && !oe.isMouseDownRight){ + oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + } +}; + +Neo.DrawToolBase.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 1.0; + Neo.updateUI(); + }; +}; + + +/* FreeHand (手書き) */ + +Neo.DrawToolBase.prototype.freeHandDownHandler = function(oe) { + //Register undo first; + oe._pushUndo(); + + oe.prepareDrawing(); + this.isUpMove = false; + var ctx = oe.canvasCtx[oe.current]; + if (oe.alpha >= 1 || this.lineType != Neo.Painter.LINETYPE_BRUSH) { + var x0 = Math.floor(oe.mouseX); + var y0 = Math.floor(oe.mouseY); + oe.drawLine(ctx, x0, y0, x0, y0, this.lineType); + } + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + + if (oe.alpha >= 1) { + var r = Math.ceil(oe.lineWidth / 2); + var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.mouseX, oe.mouseY, r); + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + } +}; + +Neo.DrawToolBase.prototype.freeHandUpHandler = function(oe) { + oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight); + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + +// oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); +// this.drawCursor(oe); + oe.prevLine = null; +}; + +Neo.DrawToolBase.prototype.freeHandMoveHandler = function(oe) { + var ctx = oe.canvasCtx[oe.current]; + var x0 = Math.floor(oe.mouseX); + var y0 = Math.floor(oe.mouseY); + var x1 = Math.floor(oe.prevMouseX); + var y1 = Math.floor(oe.prevMouseY); + oe.drawLine(ctx, x0, y0, x1, y1, this.lineType); + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + + var r = Math.ceil(oe.lineWidth / 2); + var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.prevMouseX, oe.prevMouseY, r); + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); +}; + +Neo.DrawToolBase.prototype.freeHandUpMoveHandler = function(oe) { + this.isUpMove = true; + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + this.drawCursor(oe); +}; + +Neo.DrawToolBase.prototype.drawCursor = function(oe) { + if (oe.lineWidth <= 8) return; + var mx = oe.mouseX; + var my = oe.mouseY; + var d = oe.lineWidth; + + var x = (mx - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom; + var y = (my - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom; + var r = d * 0.5 * oe.zoom; + + if (!(x > -r && + y > -r && + x < oe.destCanvas.width + r && + y < oe.destCanvas.height + r)) return; + + var ctx = oe.destCanvasCtx; + ctx.save(); + this.transformForZoom(oe) + + var c = (this.type == Neo.Painter.TOOLTYPE_ERASER) ? 0x0000ff : 0xffff7f; + oe.drawXOREllipse(ctx, x-r, y-r, r*2, r*2, false, c); + + ctx.restore(); + oe.cursorRect = oe.getBound(mx, my, mx, my, Math.ceil(d / 2)); +} + + +/* Line (直線) */ + +Neo.DrawToolBase.prototype.lineDownHandler = function(oe) { + this.isUpMove = false; + this.startX = Math.floor(oe.mouseX); + this.startY = Math.floor(oe.mouseY); + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); +}; + +Neo.DrawToolBase.prototype.lineUpHandler = function(oe) { + if (this.isUpMove == false) { + this.isUpMove = true; + + oe._pushUndo(); + oe.prepareDrawing(); + var ctx = oe.canvasCtx[oe.current]; + var x0 = Math.floor(oe.mouseX); + var y0 = Math.floor(oe.mouseY); + oe.drawLine(ctx, x0, y0, this.startX, this.startY, this.lineType); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + } +}; + +Neo.DrawToolBase.prototype.lineMoveHandler = function(oe) { + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + this.drawLineCursor(oe); +}; + +Neo.DrawToolBase.prototype.lineUpMoveHandler = function(oe) { +}; + +Neo.DrawToolBase.prototype.drawLineCursor = function(oe, mx, my) { + if (!mx) mx = Math.floor(oe.mouseX); + if (!my) my = Math.floor(oe.mouseY); + var nx = this.startX; + var ny = this.startY; + var ctx = oe.destCanvasCtx; + ctx.save(); + this.transformForZoom(oe) + + var x0 = (mx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom; + var y0 = (my +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom; + var x1 = (nx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom; + var y1 = (ny +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom; + oe.drawXORLine(ctx, x0, y0, x1, y1); + + ctx.restore(); +}; + + +/* Bezier (BZ曲線) */ + +Neo.DrawToolBase.prototype.bezierDownHandler = function(oe) { + this.isUpMove = false; + + if (this.step == 0) { + this.startX = this.x0 = Math.floor(oe.mouseX); + this.startY = this.y0 = Math.floor(oe.mouseY); + } + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); +}; + +Neo.DrawToolBase.prototype.bezierUpHandler = function(oe) { + if (this.isUpMove == false) { + this.isUpMove = true; + } + + this.step++; + switch (this.step) { + case 1: + oe.prepareDrawing(); + this.x3 = Math.floor(oe.mouseX); + this.y3 = Math.floor(oe.mouseY); + break; + + case 2: + this.x1 = Math.floor(oe.mouseX); + this.y1 = Math.floor(oe.mouseY); + break; + + case 3: + this.x2 = Math.floor(oe.mouseX); + this.y2 = Math.floor(oe.mouseY); + + oe._pushUndo(); + oe.drawBezier(oe.canvasCtx[oe.current], + this.x0, this.y0, this.x1, this.y1, + this.x2, this.y2, this.x3, this.y3, this.lineType); + + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + this.step = 0; + break; + + default: + this.step = 0; + break; + } +}; + +Neo.DrawToolBase.prototype.bezierMoveHandler = function(oe) { + switch (this.step) { + case 0: + if (!this.isUpMove) { + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false); + this.drawLineCursor(oe); + } + break; + case 1: + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false); + this.drawBezierCursor1(oe); + break; + + case 2: + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false); + this.drawBezierCursor2(oe); + break; + } +}; + +Neo.DrawToolBase.prototype.bezierUpMoveHandler = function(oe) { + this.bezierMoveHandler(oe); +}; + +Neo.DrawToolBase.prototype.bezierKeyDownHandler = function(e) { + if (e.keyCode == 27) { //Escでキャンセル + this.step = 0; + + var oe = Neo.painter; + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + } +}; + + +Neo.DrawToolBase.prototype.drawBezierCursor1 = function(oe) { + var ctx = oe.destCanvasCtx; +// var x = oe.mouseX; //Math.floor(oe.mouseX); +// var y = oe.mouseY; //Math.floor(oe.mouseY); + var stab = oe.getStabilized(); + var x = Math.floor(stab[0]); + var y = Math.floor(stab[1]); + var p = oe.getDestCanvasPosition(x, y, false, true); + var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true); + var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true); + + // handle + oe.drawXORLine(ctx, p0.x, p0.y, p.x, p.y); + oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8); + oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8); + + // preview + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.drawBezier(oe.tempCanvasCtx, + this.x0, this.y0, + x, y, + x, y, + this.x3, this.y3, this.lineType); + + ctx.save(); + ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5); + ctx.scale(oe.zoom, oe.zoom); + ctx.translate(-oe.zoomX, -oe.zoomY); + ctx.drawImage(oe.tempCanvas, + 0, 0, oe.canvasWidth, oe.canvasHeight, + 0, 0, oe.canvasWidth, oe.canvasHeight); + + ctx.restore(); +}; + +Neo.DrawToolBase.prototype.drawBezierCursor2 = function(oe) { + var ctx = oe.destCanvasCtx; +// var x = oe.mouseX; //Math.floor(oe.mouseX); +// var y = oe.mouseY; //Math.floor(oe.mouseY); + var stab = oe.getStabilized(); + var x = Math.floor(stab[0]); + var y = Math.floor(stab[1]); + var p = oe.getDestCanvasPosition(oe.mouseX, oe.mouseY, false, true); + var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true); + var p1 = oe.getDestCanvasPosition(this.x1, this.y1, false, true); + var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true); + + // handle + oe.drawXORLine(ctx, p3.x, p3.y, p.x, p.y); + oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8); + oe.drawXORLine(ctx, p0.x, p0.y, p1.x, p1.y); + oe.drawXOREllipse(ctx, p1.x - 4, p1.y - 4, 8, 8); + oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8); + + // preview + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.drawBezier(oe.tempCanvasCtx, + this.x0, this.y0, + this.x1, this.y1, + x, y, + this.x3, this.y3, this.lineType); + + ctx.save(); + ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5); + ctx.scale(oe.zoom, oe.zoom); + ctx.translate(-oe.zoomX, -oe.zoomY); + ctx.drawImage(oe.tempCanvas, + 0, 0, oe.canvasWidth, oe.canvasHeight, + 0, 0, oe.canvasWidth, oe.canvasHeight); + ctx.restore(); +}; + +/* +------------------------------------------------------------------------- + Pen(鉛筆) +------------------------------------------------------------------------- +*/ + +Neo.PenTool = function() {}; +Neo.PenTool.prototype = new Neo.DrawToolBase(); +Neo.PenTool.prototype.type = Neo.Painter.TOOLTYPE_PEN; +Neo.PenTool.prototype.lineType = Neo.Painter.LINETYPE_PEN; + +Neo.PenTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 1.0; + Neo.updateUI(); + }; +} + +/* +------------------------------------------------------------------------- + Brush(水彩) +------------------------------------------------------------------------- +*/ + +Neo.BrushTool = function() {}; +Neo.BrushTool.prototype = new Neo.DrawToolBase(); +Neo.BrushTool.prototype.type = Neo.Painter.TOOLTYPE_BRUSH; +Neo.BrushTool.prototype.lineType = Neo.Painter.LINETYPE_BRUSH; + +Neo.BrushTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = this.getAlpha(); + Neo.updateUI(); + } +}; + +Neo.BrushTool.prototype.getAlpha = function() { + var alpha = 241 - Math.floor(Neo.painter.lineWidth / 2) * 6; + return alpha / 255.0; +}; + +/* +------------------------------------------------------------------------- + Tone(トーン) +------------------------------------------------------------------------- +*/ + +Neo.ToneTool = function() {}; +Neo.ToneTool.prototype = new Neo.DrawToolBase(); +Neo.ToneTool.prototype.type = Neo.Painter.TOOLTYPE_TONE; +Neo.ToneTool.prototype.lineType = Neo.Painter.LINETYPE_TONE; + +Neo.ToneTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 23 / 255.0; + Neo.updateUI(); + } +}; + +/* +------------------------------------------------------------------------- + Eraser(消しペン) +------------------------------------------------------------------------- +*/ + +Neo.EraserTool = function() {}; +Neo.EraserTool.prototype = new Neo.DrawToolBase(); +Neo.EraserTool.prototype.type = Neo.Painter.TOOLTYPE_ERASER; +Neo.EraserTool.prototype.lineType = Neo.Painter.LINETYPE_ERASER; + + +/* +------------------------------------------------------------------------- + Blur(ぼかし) +------------------------------------------------------------------------- +*/ + +Neo.BlurTool = function() {}; +Neo.BlurTool.prototype = new Neo.DrawToolBase(); +Neo.BlurTool.prototype.type = Neo.Painter.TOOLTYPE_BLUR; +Neo.BlurTool.prototype.lineType = Neo.Painter.LINETYPE_BLUR; + +Neo.BlurTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 128 / 255.0; + Neo.updateUI(); + } +}; + +/* +------------------------------------------------------------------------- + Dodge(覆い焼き) +------------------------------------------------------------------------- +*/ + +Neo.DodgeTool = function() {}; +Neo.DodgeTool.prototype = new Neo.DrawToolBase(); +Neo.DodgeTool.prototype.type = Neo.Painter.TOOLTYPE_DODGE; +Neo.DodgeTool.prototype.lineType = Neo.Painter.LINETYPE_DODGE; + +Neo.DodgeTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 128 / 255.0; + Neo.updateUI(); + } +}; + +/* +------------------------------------------------------------------------- + Burn(焼き込み) +------------------------------------------------------------------------- +*/ + +Neo.BurnTool = function() {}; +Neo.BurnTool.prototype = new Neo.DrawToolBase(); +Neo.BurnTool.prototype.type = Neo.Painter.TOOLTYPE_BURN; +Neo.BurnTool.prototype.lineType = Neo.Painter.LINETYPE_BURN; + +Neo.BurnTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 128 / 255.0; + Neo.updateUI(); + } +}; + +/* +------------------------------------------------------------------------- + Hand(スクロール) +------------------------------------------------------------------------- +*/ + +Neo.HandTool = function() {}; +Neo.HandTool.prototype = new Neo.ToolBase(); +Neo.HandTool.prototype.type = Neo.Painter.TOOLTYPE_HAND; +Neo.HandTool.prototype.isUpMove = false; +Neo.HandTool.prototype.reverse = false; + +Neo.HandTool.prototype.downHandler = function(oe) { + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + + this.isDrag = true; + this.startX = oe.rawMouseX; + this.startY = oe.rawMouseY; +}; + +Neo.HandTool.prototype.upHandler = function(oe) { + this.isDrag = false; + oe.popTool(); +}; + +Neo.HandTool.prototype.moveHandler = function(oe) { + if (this.isDrag) { + var dx = this.startX - oe.rawMouseX; + var dy = this.startY - oe.rawMouseY; + + var ax = oe.destCanvas.width / (oe.canvasWidth * oe.zoom); + var ay = oe.destCanvas.height / (oe.canvasHeight * oe.zoom); + var barWidth = oe.destCanvas.width * ax; + var barHeight = oe.destCanvas.height * ay; + var scrollWidthInScreen = oe.destCanvas.width - barWidth - 2; + var scrollHeightInScreen = oe.destCanvas.height - barHeight - 2; + + dx *= oe.scrollWidth / scrollWidthInScreen; + dy *= oe.scrollHeight / scrollHeightInScreen; + + if (this.reverse) { + dx *= -1; + dy *= -1; + } + + oe.setZoomPosition(oe.zoomX - dx, oe.zoomY - dy); + + this.startX = oe.rawMouseX; + this.startY = oe.rawMouseY; + } +}; + +Neo.HandTool.prototype.rollOutHandler= function(oe) {}; +Neo.HandTool.prototype.upMoveHandler = function(oe) {} +Neo.HandTool.prototype.rollOverHandler= function(oe) {} + +/* +------------------------------------------------------------------------- + Slider(色やサイズのスライダを操作している時) +------------------------------------------------------------------------- +*/ + +Neo.SliderTool = function() {}; +Neo.SliderTool.prototype = new Neo.ToolBase(); +Neo.SliderTool.prototype.type = Neo.Painter.TOOLTYPE_SLIDER; +Neo.SliderTool.prototype.isUpMove = false; +Neo.SliderTool.prototype.alt = false; + +Neo.SliderTool.prototype.downHandler = function(oe) { + if (!oe.isShiftDown) this.isDrag = true; + + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + + var rect = this.target.getBoundingClientRect(); + var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider']; + Neo.sliders[sliderType].downHandler(oe.rawMouseX - rect.left, + oe.rawMouseY - rect.top); +}; + +Neo.SliderTool.prototype.upHandler = function(oe) { + this.isDrag = false; + oe.popTool(); + + var rect = this.target.getBoundingClientRect(); + var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider']; + Neo.sliders[sliderType].upHandler(oe.rawMouseX - rect.left, + oe.rawMouseY - rect.top); +}; + +Neo.SliderTool.prototype.moveHandler = function(oe) { + if (this.isDrag) { + var rect = this.target.getBoundingClientRect(); + var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider']; + Neo.sliders[sliderType].moveHandler(oe.rawMouseX - rect.left, + oe.rawMouseY - rect.top); + } +}; + +Neo.SliderTool.prototype.upMoveHandler = function(oe) {} +Neo.SliderTool.prototype.rollOutHandler= function(oe) {}; +Neo.SliderTool.prototype.rollOverHandler= function(oe) {} + +/* +------------------------------------------------------------------------- + Fill(塗り潰し) +------------------------------------------------------------------------- +*/ + +Neo.FillTool = function() {}; +Neo.FillTool.prototype = new Neo.ToolBase(); +Neo.FillTool.prototype.type = Neo.Painter.TOOLTYPE_FILL; +Neo.FillTool.prototype.isUpMove = false; + +Neo.FillTool.prototype.downHandler = function(oe) { + var x = Math.floor(oe.mouseX); + var y = Math.floor(oe.mouseY); + oe._pushUndo(); + oe.fill(x, y, oe.canvasCtx[oe.current]); +}; + +Neo.FillTool.prototype.upHandler = function(oe) { +}; + +Neo.FillTool.prototype.moveHandler = function(oe) { +}; + +Neo.FillTool.prototype.rollOutHandler= function(oe) {}; +Neo.FillTool.prototype.upMoveHandler = function(oe) {} +Neo.FillTool.prototype.rollOverHandler= function(oe) {} + + +/* +------------------------------------------------------------------------- + EraseAll(全消し) +------------------------------------------------------------------------- +*/ + +Neo.EraseAllTool = function() {}; +Neo.EraseAllTool.prototype = new Neo.ToolBase(); +Neo.EraseAllTool.prototype.type = Neo.Painter.TOOLTYPE_ERASEALL; +Neo.EraseAllTool.prototype.isUpMove = false; + +Neo.EraseAllTool.prototype.downHandler = function(oe) { + oe._pushUndo(); + + oe.prepareDrawing(); + oe.canvasCtx[oe.current].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +Neo.EraseAllTool.prototype.upHandler = function(oe) { +}; + +Neo.EraseAllTool.prototype.moveHandler = function(oe) { +}; + +Neo.EraseAllTool.prototype.rollOutHandler= function(oe) {}; +Neo.EraseAllTool.prototype.upMoveHandler = function(oe) {}; +Neo.EraseAllTool.prototype.rollOverHandler= function(oe) {}; + + +/* +------------------------------------------------------------------------- + EffectToolBase(エフェックトツールのベースクラス) +------------------------------------------------------------------------- +*/ + +Neo.EffectToolBase = function() {}; +Neo.EffectToolBase.prototype = new Neo.ToolBase(); +Neo.EffectToolBase.prototype.isUpMove = false; + +Neo.EffectToolBase.prototype.downHandler = function(oe) { + this.isUpMove = false; + + this.startX = this.endX = oe.clipMouseX; + this.startY = this.endY = oe.clipMouseY; +}; + +Neo.EffectToolBase.prototype.upHandler = function(oe) { + if (this.isUpMove) return; + this.isUpMove = true; + + this.startX = Math.floor(this.startX); + this.startY = Math.floor(this.startY); + this.endX = Math.floor(this.endX); + this.endY = Math.floor(this.endY); + + var x = (this.startX < this.endX) ? this.startX : this.endX; + var y = (this.startY < this.endY) ? this.startY : this.endY; + var width = Math.abs(this.startX - this.endX) + 1; + var height = Math.abs(this.startY - this.endY) + 1; + var ctx = oe.canvasCtx[oe.current]; + + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x + width > oe.canvasWidth) width = oe.canvasWidth - x; + if (y + height > oe.canvasHeight) height = oe.canvasHeight - y; + + if (width > 0 && height > 0) { + oe._pushUndo(); + oe.prepareDrawing(); + this.doEffect(oe, x, y, width, height); + } + + if (oe.tool.type != Neo.Painter.TOOLTYPE_PASTE) { + oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + } +}; + +Neo.EffectToolBase.prototype.moveHandler = function(oe) { + this.endX = oe.clipMouseX; + this.endY = oe.clipMouseY; + + oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + this.drawCursor(oe); +}; + +Neo.EffectToolBase.prototype.rollOutHandler= function(oe) {}; +Neo.EffectToolBase.prototype.upMoveHandler = function(oe) {}; +Neo.EffectToolBase.prototype.rollOverHandler= function(oe) {}; + +Neo.EffectToolBase.prototype.drawCursor = function(oe) { + var ctx = oe.destCanvasCtx; + + ctx.save(); + this.transformForZoom(oe); + + var start = oe.getDestCanvasPosition(this.startX, this.startY, true); + var end = oe.getDestCanvasPosition(this.endX, this.endY, true); + + var x = (start.x < end.x) ? start.x : end.x; + var y = (start.y < end.y) ? start.y : end.y; + var width = Math.abs(start.x - end.x) + oe.zoom; + var height = Math.abs(start.y - end.y) + oe.zoom; + + if (this.isEllipse) { + oe.drawXOREllipse(ctx, x, y, width, height, this.isFill); + + } else { + oe.drawXORRect(ctx, x, y, width, height, this.isFill); + } + ctx.restore(); +}; + +Neo.EffectToolBase.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = this.defaultAlpha || 1.0; + Neo.updateUI(); + }; +}; + +/* +------------------------------------------------------------------------- + EraseRect(消し四角) +------------------------------------------------------------------------- +*/ + +Neo.EraseRectTool = function() {}; +Neo.EraseRectTool.prototype = new Neo.EffectToolBase(); +Neo.EraseRectTool.prototype.type = Neo.Painter.TOOLTYPE_ERASERECT; + +Neo.EraseRectTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.eraseRect(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + FlipH(左右反転) +------------------------------------------------------------------------- +*/ + +Neo.FlipHTool = function() {}; +Neo.FlipHTool.prototype = new Neo.EffectToolBase(); +Neo.FlipHTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_H; + +Neo.FlipHTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.flipH(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + FlipV(上下反転) +------------------------------------------------------------------------- +*/ + +Neo.FlipVTool = function() {}; +Neo.FlipVTool.prototype = new Neo.EffectToolBase(); +Neo.FlipVTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_V; + +Neo.FlipVTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.flipV(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + DodgeRect(角取り) +------------------------------------------------------------------------- +*/ + +Neo.BlurRectTool = function() {}; +Neo.BlurRectTool.prototype = new Neo.EffectToolBase(); +Neo.BlurRectTool.prototype.type = Neo.Painter.TOOLTYPE_BLURRECT; + +Neo.BlurRectTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.blurRect(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +Neo.BlurRectTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 0.5; + Neo.updateUI(); + }; +} + +/* +------------------------------------------------------------------------- + Turn(傾け) +------------------------------------------------------------------------- +*/ + +Neo.TurnTool = function() {}; +Neo.TurnTool.prototype = new Neo.EffectToolBase(); +Neo.TurnTool.prototype.type = Neo.Painter.TOOLTYPE_TURN; + +Neo.TurnTool.prototype.upHandler = function(oe) { + this.isUpMove = true; + + this.startX = Math.floor(this.startX); + this.startY = Math.floor(this.startY); + this.endX = Math.floor(this.endX); + this.endY = Math.floor(this.endY); + + var x = (this.startX < this.endX) ? this.startX : this.endX; + var y = (this.startY < this.endY) ? this.startY : this.endY; + var width = Math.abs(this.startX - this.endX) + 1; + var height = Math.abs(this.startY - this.endY) + 1; + + if (width > 0 && height > 0) { + oe._pushUndo(); + oe.turn(x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + } +}; + +/* +------------------------------------------------------------------------- + Merge(レイヤー結合) +------------------------------------------------------------------------- +*/ + +Neo.MergeTool = function() {}; +Neo.MergeTool.prototype = new Neo.EffectToolBase(); +Neo.MergeTool.prototype.type = Neo.Painter.TOOLTYPE_MERGE; + +Neo.MergeTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.merge(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + Copy(コピー) +------------------------------------------------------------------------- +*/ + +Neo.CopyTool = function() {}; +Neo.CopyTool.prototype = new Neo.EffectToolBase(); +Neo.CopyTool.prototype.type = Neo.Painter.TOOLTYPE_COPY; + +Neo.CopyTool.prototype.doEffect = function(oe, x, y, width, height) { + oe.copy(x, y, width, height); + oe.setToolByType(Neo.Painter.TOOLTYPE_PASTE); + oe.tool.x = x; + oe.tool.y = y; + oe.tool.width = width; + oe.tool.height = height; +}; + +/* +------------------------------------------------------------------------- + Paste(ペースト) +------------------------------------------------------------------------- +*/ + +Neo.PasteTool = function() {}; +Neo.PasteTool.prototype = new Neo.ToolBase(); +Neo.PasteTool.prototype.type = Neo.Painter.TOOLTYPE_PASTE; + +Neo.PasteTool.prototype.downHandler = function(oe) { + this.startX = oe.mouseX; + this.startY = oe.mouseY; + this.drawCursor(oe); +}; + +Neo.PasteTool.prototype.upHandler = function(oe) { + oe._pushUndo(); + + oe.paste(this.x, this.y, this.width, this.height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + + oe.setToolByType(Neo.Painter.TOOLTYPE_COPY); +}; + +Neo.PasteTool.prototype.moveHandler = function(oe) { + var dx = Math.floor(oe.mouseX - this.startX); + var dy = Math.floor(oe.mouseY - this.startY); + oe.tempX = dx; + oe.tempY = dy; + + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +// this.drawCursor(oe); +}; + +Neo.PasteTool.prototype.keyDownHandler = function(e) { + if (e.keyCode == 27) { //Escでキャンセル + var oe = Neo.painter; + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + oe.setToolByType(Neo.Painter.TOOLTYPE_COPY); + } +}; + +Neo.PasteTool.prototype.drawCursor = function(oe) { + var ctx = oe.destCanvasCtx; + + ctx.save(); + this.transformForZoom(oe); + + var start = oe.getDestCanvasPosition(this.x, this.y, true); + var end = oe.getDestCanvasPosition(this.x + this.width, this.y + this.height, true); + + var x = start.x + oe.tempX * oe.zoom; + var y = start.y + oe.tempY * oe.zoom; + var width = Math.abs(start.x - end.x); + var height = Math.abs(start.y - end.y); + oe.drawXORRect(ctx, x, y, width, height); + ctx.restore(); +}; + +/* +------------------------------------------------------------------------- + Rect(線四角) +------------------------------------------------------------------------- +*/ + +Neo.RectTool = function() {}; +Neo.RectTool.prototype = new Neo.EffectToolBase(); +Neo.RectTool.prototype.type = Neo.Painter.TOOLTYPE_RECT; + +Neo.RectTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.rectMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + RectFill(四角) +------------------------------------------------------------------------- +*/ + +Neo.RectFillTool = function() {}; +Neo.RectFillTool.prototype = new Neo.EffectToolBase(); +Neo.RectFillTool.prototype.type = Neo.Painter.TOOLTYPE_RECTFILL; + +Neo.RectFillTool.prototype.isFill = true; +Neo.RectFillTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.rectFillMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + Ellipse(線楕円) +------------------------------------------------------------------------- +*/ + +Neo.EllipseTool = function() {}; +Neo.EllipseTool.prototype = new Neo.EffectToolBase(); +Neo.EllipseTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSE; +Neo.EllipseTool.prototype.isEllipse = true; +Neo.EllipseTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.ellipseMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + EllipseFill(楕円) +------------------------------------------------------------------------- +*/ + +Neo.EllipseFillTool = function() {}; +Neo.EllipseFillTool.prototype = new Neo.EffectToolBase(); +Neo.EllipseFillTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSEFILL; +Neo.EllipseFillTool.prototype.isEllipse = true; +Neo.EllipseFillTool.prototype.isFill = true; +Neo.EllipseFillTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.ellipseFillMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* +------------------------------------------------------------------------- + Text(テキスト) +------------------------------------------------------------------------- +*/ + +Neo.TextTool = function() {}; +Neo.TextTool.prototype = new Neo.ToolBase(); +Neo.TextTool.prototype.type = Neo.Painter.TOOLTYPE_TEXT; +Neo.TextTool.prototype.isUpMove = false; + +Neo.TextTool.prototype.downHandler = function(oe) { + this.startX = oe.mouseX; + this.startY = oe.mouseY; + + if (Neo.painter.inputText) { + Neo.painter.updateInputText(); + + var rect = oe.container.getBoundingClientRect(); + var text = Neo.painter.inputText; + var x = oe.rawMouseX - rect.left - 5; + var y = oe.rawMouseY - rect.top - 5; + + text.style.left = x + "px"; + text.style.top = y + "px"; + text.style.display = "block"; + text.focus(); + } +}; + +Neo.TextTool.prototype.upHandler = function(oe) { +}; + +Neo.TextTool.prototype.moveHandler = function(oe) {}; +Neo.TextTool.prototype.upMoveHandler = function(oe) {}; +Neo.TextTool.prototype.rollOverHandler= function(oe) {}; +Neo.TextTool.prototype.rollOutHandler= function(oe) {}; + +Neo.TextTool.prototype.keyDownHandler = function(e) { + if (e.keyCode == 13) { // Returnで確定 + e.preventDefault(); + + var oe = Neo.painter; + var text = oe.inputText; + if (text) { + oe._pushUndo(); + this.drawText(oe); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + + text.style.display = "none"; + text.blur(); + } + } +}; + +Neo.TextTool.prototype.kill = function(oe) { + Neo.painter.hideInputText(); +}; + +Neo.TextTool.prototype.drawText = function(oe) { + var text = oe.inputText; + + // unescape entities + //var tmp = document.createElement("textarea"); + //tmp.innerHTML = text.innerHTML; + //var string = tmp.value; + + var string = text.textContent || text.innerText; + + if (string.length <= 0) return; + oe.doText(this.startX, this.startY, string, text.style.fontSize); +}; + +Neo.TextTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 1.0; + Neo.updateUI(); + }; +}; + +/* +------------------------------------------------------------------------- + Dummy(何もしない時) +------------------------------------------------------------------------- +*/ + +Neo.DummyTool = function() {}; +Neo.DummyTool.prototype = new Neo.ToolBase(); +Neo.DummyTool.prototype.type = Neo.Painter.TOOLTYPE_NONE; +Neo.DummyTool.prototype.isUpMove = false; + +Neo.DummyTool.prototype.downHandler = function(oe) { +}; + +Neo.DummyTool.prototype.upHandler = function(oe) { + oe.popTool(); +}; + +Neo.DummyTool.prototype.moveHandler = function(oe) {}; +Neo.DummyTool.prototype.upMoveHandler = function(oe) {} +Neo.DummyTool.prototype.rollOverHandler= function(oe) {} +Neo.DummyTool.prototype.rollOutHandler= function(oe) {} + +'use strict'; + +Neo.CommandBase = function() { +}; +Neo.CommandBase.prototype.data; +Neo.CommandBase.prototype.execute = function() {} + + +/* +--------------------------------------------------- + ZOOM +--------------------------------------------------- +*/ +Neo.ZoomPlusCommand = function(data) {this.data = data}; +Neo.ZoomPlusCommand.prototype = new Neo.CommandBase(); +Neo.ZoomPlusCommand.prototype.execute = function() { + if (this.data.zoom < 12) { + this.data.setZoom(this.data.zoom + 1); + } + Neo.resizeCanvas(); + Neo.painter.updateDestCanvas(); +}; + +Neo.ZoomMinusCommand = function(data) {this.data = data}; +Neo.ZoomMinusCommand.prototype = new Neo.CommandBase(); +Neo.ZoomMinusCommand.prototype.execute = function() { + if (this.data.zoom >= 2) { + this.data.setZoom(this.data.zoom - 1); + } + Neo.resizeCanvas(); + Neo.painter.updateDestCanvas(); +}; + +/* +--------------------------------------------------- + UNDO +--------------------------------------------------- +*/ +Neo.UndoCommand = function(data) {this.data = data}; +Neo.UndoCommand.prototype = new Neo.CommandBase(); +Neo.UndoCommand.prototype.execute = function() { + this.data.undo(); +}; + +Neo.RedoCommand = function(data) {this.data = data}; +Neo.RedoCommand.prototype = new Neo.CommandBase(); +Neo.RedoCommand.prototype.execute = function() { + this.data.redo(); +}; + + +/* +--------------------------------------------------- +--------------------------------------------------- +*/ + + + +Neo.WindowCommand = function(data) {this.data = data}; +Neo.WindowCommand.prototype = new Neo.CommandBase(); +Neo.WindowCommand.prototype.execute = function() { + if (Neo.fullScreen) { + //if (confirm("¿Vista página?")) { + Neo.fullScreen = false; + Neo.updateWindow(); + //} + } else { + //if (confirm("¿Vista ventana?")) { + Neo.fullScreen = true; + Neo.updateWindow(); + //} + } +}; + +Neo.SubmitCommand = function(data) {this.data = data}; +Neo.SubmitCommand.prototype = new Neo.CommandBase(); +Neo.SubmitCommand.prototype.execute = function() { + var board = location.href.replace(/[^/]*$/, ''); + console.log("submit: " + board); + this.data.submit(board); +}; + +Neo.CopyrightCommand = function(data) {this.data = data}; +Neo.CopyrightCommand.prototype = new Neo.CommandBase(); +Neo.CopyrightCommand.prototype.execute = function() { +// var url = "http://hp.vector.co.jp/authors/VA016309/"; +// if (confirm(url + "\nしぃちゃんのホームページを表示しますか?")) { + var url = "http://github.com/funige/neo/"; + if (confirm("PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?" + "\n")) { + Neo.openURL(url); + } +}; + +'use strict'; + +/* +------------------------------------------------------------------------- + Button +------------------------------------------------------------------------- +*/ + +Neo.Button = function() {}; +Neo.Button.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.selected = false; + this.isMouseDown = false; + + var ref = this; + if (window.PointerEvent) { + this.element.onpointerdown = function(e) { ref._mouseDownHandler(e); } + this.element.onpointerup = function(e) { ref._mouseUpHandler(e); } + this.element.onpointerover = function(e) { ref._mouseOverHandler(e); } + this.element.onpointerout = function(e) { ref._mouseOutHandler(e); } + + } else { + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.onmouseup = function(e) { ref._mouseUpHandler(e); } + this.element.onmouseover = function(e) { ref._mouseOverHandler(e); } + this.element.onmouseout = function(e) { ref._mouseOutHandler(e); } + } + this.element.className = (!this.params.type == 'fill') ? "button" : "buttonOff"; + + return this; +}; + +Neo.Button.prototype._mouseDownHandler = function(e) { + if (Neo.painter.isUIPaused()) return; + this.isMouseDown = true; + + if ((this.params.type == "fill") && (this.selected == false)) { + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + toolTip.setSelected((this.selected) ? false : true); + } + Neo.painter.setToolByType(Neo.Painter.TOOLTYPE_FILL); + } + + if (this.onmousedown) this.onmousedown(this); +}; +Neo.Button.prototype._mouseUpHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + + if (this.onmouseup) this.onmouseup(this); + } +}; +Neo.Button.prototype._mouseOutHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseout) this.onmouseout(this); + } +}; +Neo.Button.prototype._mouseOverHandler = function(e) { + if (this.onmouseover) this.onmouseover(this); +}; + +Neo.Button.prototype.setSelected = function(selected) { + if (selected) { + this.element.className = "buttonOn"; + } else { + this.element.className = "buttonOff"; + } + this.selected = selected; +}; + +Neo.Button.prototype.update = function() { +}; + +/* +------------------------------------------------------------------------- + ColorTip +------------------------------------------------------------------------- +*/ + +Neo.colorTips = []; + +Neo.ColorTip = function() {}; +Neo.ColorTip.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + + this.selected = (this.name == "color1") ? true : false; + this.isMouseDown = false; + + var ref = this; + if (window.PointerEvent) { + this.element.onpointerdown = function(e) { ref._mouseDownHandler(e); } + this.element.onpointerup = function(e) { ref._mouseUpHandler(e); } + this.element.onpointerover = function(e) { ref._mouseOverHandler(e); } + this.element.onpointerout = function(e) { ref._mouseOutHandler(e); } + + } else { + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.onmouseup = function(e) { ref._mouseUpHandler(e); } + this.element.onmouseover = function(e) { ref._mouseOverHandler(e); } + this.element.onmouseout = function(e) { ref._mouseOutHandler(e); } + } + this.element.className = "colorTipOff"; + + var index = parseInt(this.name.slice(5)) - 1; + this.element.style.left = (index % 2) ? "0px" : "26px"; + this.element.style.top = Math.floor(index / 2) * 21 + "px"; + + // base64 ColorTip.png + this.element.innerHTML = "<img style='max-width:44px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAASCAYAAAAg9DzcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANklEQVRIx+3OAQkAMADDsO3+Pe8qCj+0Akq6bQFqS2wTCpwE+R4IiyVYsGDBggULfirBgn8HX7BzCRwDx1QeAAAAAElFTkSuQmCC' />" + + this.setColor(Neo.config.colors[params.index - 1]); + + this.setSelected(this.selected); + Neo.colorTips.push(this); +}; + +Neo.ColorTip.prototype._mouseDownHandler = function(e) { + if (Neo.painter.isUIPaused()) return; + this.isMouseDown = true; + + for (var i = 0; i < Neo.colorTips.length; i++) { + var colorTip = Neo.colorTips[i]; + if (this == colorTip) { + if (e.shiftKey) { + this.setColor(Neo.config.colors[this.params.index - 1]); + } else if (e.button == 2 || e.ctrlKey || e.altKey) { + this.setColor(Neo.painter.foregroundColor); + } + } + colorTip.setSelected(this == colorTip) ? true : false; + } + Neo.painter.setColor(this.color); + Neo.updateUIColor(true, false); + + if (this.onmousedown) this.onmousedown(this); +}; +Neo.ColorTip.prototype._mouseUpHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseup) this.onmouseup(this); + } +}; +Neo.ColorTip.prototype._mouseOutHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseout) this.onmouseout(this); + } +}; +Neo.ColorTip.prototype._mouseOverHandler = function(e) { + if (this.onmouseover) this.onmouseover(this); +}; + +Neo.ColorTip.prototype.setSelected = function(selected) { + if (selected) { + this.element.className = "colorTipOn"; + } else { + this.element.className = "colorTipOff"; + } + this.selected = selected; +}; + +Neo.ColorTip.prototype.setColor = function(color) { + this.color = color; + this.element.style.backgroundColor = color; +}; + +Neo.ColorTip.getCurrent = function() { + for (var i = 0; i < Neo.colorTips.length; i++) { + var colorTip = Neo.colorTips[i]; + if (colorTip.selected) return colorTip; + } + return null; +}; + +/* +------------------------------------------------------------------------- + ToolTip +------------------------------------------------------------------------- +*/ + +Neo.toolTips = []; +Neo.toolButtons = []; + +Neo.ToolTip = function() {}; + +Neo.ToolTip.prototype.prevMode = -1; + +Neo.ToolTip.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.params.type = this.element.id; + this.name = name; + this.mode = 0; + + this.isMouseDown = false; + + var ref = this; + if (window.PointerEvent) { + this.element.onpointerdown = function(e) { ref._mouseDownHandler(e); } + this.element.onpointerup = function(e) { ref._mouseUpHandler(e); } + this.element.onpointerover = function(e) { ref._mouseOverHandler(e); } + this.element.onpointerout = function(e) { ref._mouseOutHandler(e); } + + } else { + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.onmouseup = function(e) { ref._mouseUpHandler(e); } + this.element.onmouseover = function(e) { ref._mouseOverHandler(e); } + this.element.onmouseout = function(e) { ref._mouseOutHandler(e); } + } + this.selected = (this.params.type == "pen") ? true : false; + this.setSelected(this.selected); + + this.element.innerHTML = "<canvas width=46 height=18></canvas><div class='label'></div>"; + this.canvas = this.element.getElementsByTagName('canvas')[0]; + this.label = this.element.getElementsByTagName('div')[0]; + + this.update(); + return this; +}; + +Neo.ToolTip.prototype._mouseDownHandler = function(e) { + this.isMouseDown = true; + + if (this.isTool) { + if (this.selected == false) { + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + toolTip.setSelected((this == toolTip) ? true : false); + } + + } else { + var length = this.toolStrings.length; + if (e.button == 2 || e.ctrlKey || e.altKey) { + this.mode--; + if (this.mode < 0) this.mode = length - 1; + } else { + this.mode++; + if (this.mode >= length) this.mode = 0; + } + } + Neo.painter.setToolByType(this.tools[this.mode]); + this.update(); + } + + if (this.onmousedown) this.onmousedown(this); +}; + +Neo.ToolTip.prototype._mouseUpHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseup) this.onmouseup(this); + } +}; + +Neo.ToolTip.prototype._mouseOutHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseout) this.onmouseout(this); + } +}; +Neo.ToolTip.prototype._mouseOverHandler = function(e) { + if (this.onmouseover) this.onmouseover(this); +}; + +Neo.ToolTip.prototype.setSelected = function(selected) { + if (this.fixed) { + this.element.className = "toolTipFixed"; + + } else { + if (selected) { + this.element.className = "toolTipOn"; + } else { + this.element.className = "toolTipOff"; + } + } + this.selected = selected; +}; + +Neo.ToolTip.prototype.update = function() {}; + +Neo.ToolTip.prototype.draw = function(c) { + if (this.hasTintImage) { + if (typeof c != "string") c = Neo.painter.getColorString(c); + var ctx = this.canvas.getContext("2d"); + + if (this.prevMode != this.mode) { + this.prevMode = this.mode; + + var img = new Image(); + img.src = this.toolIcons[this.mode]; + img.onload = function() { + var ref = this; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.drawTintImage(ctx, img, c, 0, 0); + }.bind(this); + + } else { + this.tintImage(ctx, c); + } + } +}; + +Neo.ToolTip.prototype.drawTintImage = function(ctx, img, c, x, y) { + ctx.drawImage(img, x, y); + this.tintImage(ctx, c); +}; + +Neo.ToolTip.prototype.tintImage = function(ctx, c) { + c = (Neo.painter.getColor(c) & 0xffffff); + + var imageData = ctx.getImageData(0, 0, 46, 18); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + for (var i = 0; i < buf32.length; i++) { + var a = buf32[i] & 0xff000000; + if (a) { + buf32[i] = buf32[i] & a | c; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); +}; + +Neo.ToolTip.bezier = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAT0lEQVRIx+3SQQoAIAhE0en+h7ZVEEKBZrX5b5sjKknAkRYpNslaMLPq44ZI9wwHs0vMQ/v87u0Kk8xfsaI242jbMdjPi5Y0r/zTAAAAD3UOjRf9jcO4sgAAAABJRU5ErkJggg=="; +Neo.ToolTip.blur = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAASUlEQVRIx+3VMQ4AIAgEQeD/f8bWWBnJYUh2SgtgK82G8/MhzVKwxOtTLgIUx6tDout4laiPIICA0Qj4bXxAy0+8LZP9yACAJwsqkggS55eiZgAAAABJRU5ErkJggg=="; +Neo.ToolTip.blurrect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAX0lEQVRIx+2XQQ4AEAwEt+I7/v+8Org6lJKt6NzLjjYE8DAKtLpYoDeCCCC7tYUd3ru2qQOzDTyndhJzB6KSAmxSgM0fAlGuzBnmlziqxB8jFJkUYJMCbAQYPxt2kF06fvYKgjPBO/IAAAAASUVORK5CYII="; +Neo.ToolTip.brush = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQUlEQVRIx2NgGOKAEcb4z8CweRA4xpdUPSxofJ8BdP8WcjQxDaCDqQLQY4CsUBgFo2AUjIJRMApGwSgYBaNgZAIA0CoDwDbZu8oAAAAASUVORK5CYII="; +Neo.ToolTip.burn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAPklEQVRIx+3PMRIAMAQAQbzM0/0sKZPeiDG57TQ4keH0Htx9VR+MCM1vOezl8xUsv4IAAkYjoBsB3QgAgL9tYXgF19rh9yoAAAAASUVORK5CYII="; +Neo.ToolTip.copy = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XMQoAIAwDU/E7/v95Orh2KMUSC7m5Qs6AUqAxG1gzOLirwxhgmXOjOlg1oQY8sjf2mvYNSICNBNhIgE3oH/jlzfdo34AE2EiATXsBA+5mww6S5QASDwSGMt8ouwAAAABJRU5ErkJggg=="; +Neo.ToolTip.copy2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAN0lEQVRIx+3PwQkAIBADwdPKt3MtQVCOPNz5B7JV0pNxOwRW9zng+G92n+hmQJoBaQakGSBJf9tyBgQUV/fKCAAAAABJRU5ErkJggg=="; +Neo.ToolTip.ellipse = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAATklEQVRIx+2VMQ4AIAgD6/8fjbOJi1LFmt4OPQ0KIE7LNgggCBLbHkuFM9lM+Om+QwDjpksyb4tT86vlvzgEbYxefQPyv5D8HjDGGGOk6b3jJ+lYubd8AAAAAElFTkSuQmCC"; +Neo.ToolTip.ellipsefill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAVUlEQVRIx+2VURIAEAgFc/9D5waSHpV5+43ZHRMizRnRA1REARLHHq6NCFl01Nail+LeEDMgU34nYhlQQd6K+PsGKkSEZyArBPoK3Y6K/AOEEEJIayZHbhIKjkZrFwAAAABJRU5ErkJggg=="; +Neo.ToolTip.eraser = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAABQElEQVRIx+1WQY7CMAwcI37Cad+yXOgH4Gu8gAt9CtrDirfMHjZJbbcktVSpQnROSeMkY3vsFHhzSG3xfLpz/JVmG0mIqDkIMcc6+7Kejx6fdb0dq7w09rVFkrjejrMOunQ9vg7f/5QEIAd6E1Eo38WF8fF7n8sdALCrLerIzoFI4sI0Vtv1SYZ8CVbeF7tzF7JugIkVkxOauc6CIe8842S+XmMfsq7TN9LRTngZmTmVD4SrnzYaGYhFoxCWgajXuMjYGTuJ3dlwIBIN3U0cUVqLXCs5E7YeVsvAYJul5HWeLUhL3EpstQwooqoOTEHDOebpMn7ngkUsg3RotU8X1MkuVDrYohkIupC0YArX6T+PfX3kcbQLNV/iCKi6EB3xqXdAZ0JKthZ8B0QEl673NIEX/0I/z36Rf6ENGzZ8EP4A8Lp+9e9VWC4AAAAASUVORK5CYII="; +Neo.ToolTip.flip = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAZklEQVRIx+2XQQoAIAgE1+g7/f95degWHSyTTXDOhTsSiUBgOtCq8mD3DiOA3NxTCVgKaLA0qHiFOsHSnC8ELKQAmxRgE15APQfWv9pzLjwX+CXsjvBPKAXYpACb8AICzM2GHeSWAfVOCIiJuQ9tAAAAAElFTkSuQmCC"; +Neo.ToolTip.freehand = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAdUlEQVRIx+2WUQrAMAhD3dj9r+y+VoSyLhYDynzQv1qiJlCR4hzeAhVRsiC3Jkj0c5hN7Lx7IQ9SphLE1ICdwko420purEWQuywN3pqxgcw2+WwAtU1GzoqiLZNwZBvMAIcO8y3YKUO8mkbmjPzjK9E0TUPjBoeyLAS0usjLAAAAAElFTkSuQmCC"; +Neo.ToolTip.line = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAU0lEQVRIx+2UQQ4AIAjD8P+PxivRGDQC47C+oN1hIgTLQAt4qIga2c23XYAVPkm3CVhlb4ShAa/rQgMi1i0NyFg3LaBq3bAA1LpfAd7/EkIIIR2YXFYSCpWS8w8AAAAASUVORK5CYII="; +Neo.ToolTip.merge = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XQQrAQAgDx9Lv9JF9+e6h54IINlgyZ4UMOYgwmAXXmRxc3WECorJ3dAfrJtXAC7c6PPygAQuosYAaC6hJ3YHqlfyC8Q1YQI0F1IwXCHg+G3WQKhvwgwUFmFyYbwAAAABJRU5ErkJggg=="; +Neo.ToolTip.pen = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAK0lEQVRIx+3OsQkAMAwDQXn/oe3WfSAEctd9I5TA32pHJ/3AoTpfAQCAGwaa5AICJLKWSQAAAABJRU5ErkJggg=="; +Neo.ToolTip.rect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQElEQVRIx+3TMQ4AIAhD0WK8/5VxdcIYY8rw3wok7YAEr6iGKaU74BY0ro+6FKhyDHe4VxRwm6eFLn8AAADwwQIwTQgGo9ZMywAAAABJRU5ErkJggg=="; +Neo.ToolTip.rectfill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANElEQVRIx+3PIQ4AIBADwcL//3xYBMEgLiQztmab0GvcxkqqO3ALPbbO7rBXDnRzAADgYwvqDwIMJlGb5QAAAABJRU5ErkJggg=="; +Neo.ToolTip.text = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAcUlEQVRIx+2VwQ7AIAhDy7L//2V2WmIYg+ky2KEv8aCCqYQqQMgrJNpUQMXEKKDmAPHyspgSrBBvLZu3cQqZEdwhfusq0KdkVR5HlFfBvpI0mtIzeusFot7vFPqYuzZYMXUFlzc+qrIn7tf/ACGEkIwDlEQ94YZjzcgAAAAASUVORK5CYII="; +Neo.ToolTip.tone = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAO0lEQVRIx+3PIQ4AMAgEwaP//zNVVZUELiQ7CgWstFy8IaVsPhT1Lb/T+fQEAtwIcCPAjQC39QEAgJIL6DQCFhAqsRkAAAAASUVORK5CYII="; + +/* +------------------------------------------------------------------------- + PenTip +------------------------------------------------------------------------- +*/ + +Neo.penTip; + +Neo.PenTip = function() {}; +Neo.PenTip.prototype = new Neo.ToolTip(); + +Neo.PenTip.prototype.toolStrings = ["Lapiz", "Acuarela", "Texto"]; +Neo.PenTip.prototype.tools = [Neo.Painter.TOOLTYPE_PEN, + Neo.Painter.TOOLTYPE_BRUSH, + Neo.Painter.TOOLTYPE_TEXT]; + +Neo.PenTip.prototype.hasTintImage = true; +Neo.PenTip.prototype.toolIcons = [Neo.ToolTip.pen, + Neo.ToolTip.brush, + Neo.ToolTip.text]; + +Neo.PenTip.prototype.init = function(name, params) { + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.PenTip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + this.draw(Neo.painter.foregroundColor); + if (this.label) { + this.label.innerHTML = this.toolStrings[this.mode]; + } +}; + +/* +------------------------------------------------------------------------- + Pen2Tip +------------------------------------------------------------------------- +*/ + +Neo.pen2Tip; + +Neo.Pen2Tip = function() {}; +Neo.Pen2Tip.prototype = new Neo.ToolTip(); + +Neo.Pen2Tip.prototype.toolStrings = ["Tono", + "Gradacion", + "Sobreexp.", + "Quemar"]; +Neo.Pen2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_TONE, + Neo.Painter.TOOLTYPE_BLUR, + Neo.Painter.TOOLTYPE_DODGE, + Neo.Painter.TOOLTYPE_BURN]; + +Neo.Pen2Tip.prototype.hasTintImage = true; +Neo.Pen2Tip.prototype.toolIcons = [Neo.ToolTip.tone, + Neo.ToolTip.blur, + Neo.ToolTip.burn, + Neo.ToolTip.burn]; + +Neo.Pen2Tip.prototype.init = function(name, params) { + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.Pen2Tip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + switch (this.tools[this.mode]) { + case Neo.Painter.TOOLTYPE_TONE: + this.drawTone(Neo.painter.foregroundColor); + break; + + case Neo.Painter.TOOLTYPE_DODGE: + this.draw(0xffc0c0c0); + break; + + case Neo.Painter.TOOLTYPE_BURN: + this.draw(0xff404040); + break; + + default: + this.draw(Neo.painter.foregroundColor); + break; + } + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +Neo.Pen2Tip.prototype.drawTone = function() { + var ctx = this.canvas.getContext("2d"); + + var imageData = ctx.getImageData(0, 0, 46, 18); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var c = Neo.painter.getColor() | 0xff000000; + var a = Math.floor(Neo.painter.alpha * 255); + var toneData = Neo.painter.getToneData(a); + + for (var j = 0; j < 18; j++) { + for (var i = 0; i < 46; i++) { + if (j >= 1 && j < 12 && + i >= 2 && i < 26 && + toneData[(i%4) + (j%4) * 4]) { + buf32[j * 46 + i] = c; + + } else { + buf32[j * 46 + i] = 0; + } + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + + this.prevMode = this.mode; +}; + + +/* +------------------------------------------------------------------------- + EraserTip +------------------------------------------------------------------------- +*/ + +Neo.eraserTip; + +Neo.EraserTip = function() {}; +Neo.EraserTip.prototype = new Neo.ToolTip(); + +Neo.EraserTip.prototype.toolStrings = ["Goma", "Goma", "Borrar"]; +Neo.EraserTip.prototype.tools = [Neo.Painter.TOOLTYPE_ERASER, + Neo.Painter.TOOLTYPE_ERASERECT, + Neo.Painter.TOOLTYPE_ERASEALL]; + +Neo.EraserTip.prototype.init = function(name, params) { + this.drawOnce = false; + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.EraserTip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + if (this.drawOnce == false) { + this.draw(); + this.drawOnce = true; + } + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +Neo.EraserTip.prototype.draw = function() { + var ctx = this.canvas.getContext("2d"); + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + var img = new Image(); + + img.src = Neo.ToolTip.eraser; + img.onload = function() { + ctx.drawImage(img, 0, 0); + }; +}; + +/* +------------------------------------------------------------------------- + EffectTip +------------------------------------------------------------------------- +*/ + +Neo.effectTip; + +Neo.EffectTip = function() {}; +Neo.EffectTip.prototype = new Neo.ToolTip(); + +Neo.EffectTip.prototype.toolStrings = ["Cuadrado", "Cuadrado", "Circulo", "Circulo"]; +Neo.EffectTip.prototype.tools = [Neo.Painter.TOOLTYPE_RECTFILL, + Neo.Painter.TOOLTYPE_RECT, + Neo.Painter.TOOLTYPE_ELLIPSEFILL, + Neo.Painter.TOOLTYPE_ELLIPSE]; + +Neo.EffectTip.prototype.hasTintImage = true; +Neo.EffectTip.prototype.toolIcons = [Neo.ToolTip.rectfill, + Neo.ToolTip.rect, + Neo.ToolTip.ellipsefill, + Neo.ToolTip.ellipse]; + +Neo.EffectTip.prototype.init = function(name, params) { + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.EffectTip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + this.draw(Neo.painter.foregroundColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +/* +------------------------------------------------------------------------- + Effect2Tip +------------------------------------------------------------------------- +*/ + +Neo.effect2Tip; + +Neo.Effect2Tip = function() {}; +Neo.Effect2Tip.prototype = new Neo.ToolTip(); + +Neo.Effect2Tip.prototype.toolStrings = ["Copiar", "Unir", + "Cortar", + "Inv. Izq/Der", "Inv. Arr/Aba", "Inclinar"]; +Neo.Effect2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_COPY, + Neo.Painter.TOOLTYPE_MERGE, + Neo.Painter.TOOLTYPE_BLURRECT, + Neo.Painter.TOOLTYPE_FLIP_H, + Neo.Painter.TOOLTYPE_FLIP_V, + Neo.Painter.TOOLTYPE_TURN]; + +Neo.Effect2Tip.prototype.hasTintImage = true; +Neo.Effect2Tip.prototype.toolIcons = [Neo.ToolTip.copy, + Neo.ToolTip.merge, + Neo.ToolTip.blurrect, + Neo.ToolTip.flip, + Neo.ToolTip.flip, + Neo.ToolTip.flip]; + +Neo.Effect2Tip.prototype.init = function(name, params) { + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + + this.img = document.createElement("img"); + this.img.src = Neo.ToolTip.copy2; + this.element.appendChild(this.img); + return this; +}; + +Neo.Effect2Tip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + this.draw(Neo.painter.foregroundColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +/* +------------------------------------------------------------------------- + MaskTip +------------------------------------------------------------------------- +*/ + +Neo.maskTip; + +Neo.MaskTip = function() {}; +Neo.MaskTip.prototype = new Neo.ToolTip(); + +Neo.MaskTip.prototype.toolStrings = ["Normal", "Masc.", "Masc. Inv.", "Adicion", "Substrac"]; + +Neo.MaskTip.prototype.init = function(name, params) { + this.fixed = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.MaskTip.prototype._mouseDownHandler = function(e) { + this.isMouseDown = true; + + if (e.button == 2 || e.ctrlKey || e.altKey) { + Neo.painter.maskColor = Neo.painter.foregroundColor; + + } else { + var length = this.toolStrings.length; + this.mode++; + if (this.mode >= length) this.mode = 0; + Neo.painter.maskType = this.mode; + } + this.update(); + + if (this.onmousedown) this.onmousedown(this); +} + +Neo.MaskTip.prototype.update = function() { + this.draw(Neo.painter.maskColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +Neo.MaskTip.prototype.draw = function(c) { + if (typeof c != "string") c = Neo.painter.getColorString(c); + + var ctx = this.canvas.getContext("2d"); + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + ctx.fillStyle = c; + ctx.fillRect(1, 1, 43, 9); +}; + +/* +------------------------------------------------------------------------- + DrawTip +------------------------------------------------------------------------- +*/ + +Neo.drawTip; + +Neo.DrawTip = function() {}; +Neo.DrawTip.prototype = new Neo.ToolTip(); + +Neo.DrawTip.prototype.toolStrings = ["Libre", "Linea", "Curva"]; + +Neo.DrawTip.prototype.hasTintImage = true; +Neo.DrawTip.prototype.toolIcons = [Neo.ToolTip.freehand, + Neo.ToolTip.line, + Neo.ToolTip.bezier]; + +Neo.DrawTip.prototype.init = function(name, params) { + this.fixed = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.DrawTip.prototype._mouseDownHandler = function(e) { + this.isMouseDown = true; + + var length = this.toolStrings.length; + if (e.button == 2 || e.ctrlKey || e.altKey) { + this.mode--; + if (this.mode < 0) this.mode = length - 1; + } else { + this.mode++; + if (this.mode >= length) this.mode = 0; + } + Neo.painter.drawType = this.mode; + this.update(); + + if (this.onmousedown) this.onmousedown(this); +} + +Neo.DrawTip.prototype.update = function() { + this.mode = Neo.painter.drawType; + this.draw(Neo.painter.foregroundColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +/* +------------------------------------------------------------------------- + ColorSlider +------------------------------------------------------------------------- +*/ + +Neo.sliders = []; + +Neo.ColorSlider = function() {}; + +Neo.ColorSlider.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.isMouseDown = false; + this.value = 0; + this.type = this.params.type; + + this.element.className = "colorSlider"; + this.element.innerHTML = "<div class='slider'></div><div class='label'></div>"; + this.element.innerHTML += "<div class='hit'></div>"; + + this.slider = this.element.getElementsByClassName('slider')[0]; + this.label = this.element.getElementsByClassName('label')[0]; + this.hit = this.element.getElementsByClassName('hit')[0]; + this.hit['data-slider'] = params.type; + + switch (this.type) { + case Neo.SLIDERTYPE_RED: + this.prefix = "R"; + this.slider.style.backgroundColor = "#fa9696"; + break; + case Neo.SLIDERTYPE_GREEN: + this.prefix = "G"; + this.slider.style.backgroundColor = "#82f238"; + break; + case Neo.SLIDERTYPE_BLUE: + this.prefix = "B"; + this.slider.style.backgroundColor = "#8080ff"; + break; + case Neo.SLIDERTYPE_ALPHA: + this.prefix = "A"; + this.slider.style.backgroundColor = "#aaaaaa"; + this.value = 255; + break; + } + + this.update(); + return this; +}; + +Neo.ColorSlider.prototype.downHandler = function(x, y) { + if (Neo.painter.isShiftDown) { + this.shift(x, y); + + } else { + this.slide(x, y); + } +}; + +Neo.ColorSlider.prototype.moveHandler = function(x, y) { + this.slide(x, y); +}; + +Neo.ColorSlider.prototype.upHandler = function(x, y) { +}; + +Neo.ColorSlider.prototype.shift = function(x, y) { + var value; + if (x >= 0 && x < 60 && y >= 0 && y <= 15) { + var v = Math.floor((x - 5) * 5.0); + var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0; + + value = Math.max(Math.min(v, 255), min); + if (this.value > value || this.value == 255) { + this.value--; + } else { + this.value++; + } + this.value = Math.max(Math.min(this.value, 255), min); + this.value0 = this.value; + this.x0 = x; + } + + if (this.type == Neo.SLIDERTYPE_ALPHA) { + Neo.painter.alpha = this.value / 255.0; + this.update(); + Neo.updateUIColor(false, false); + + } else { + var r = Neo.sliders[Neo.SLIDERTYPE_RED].value; + var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value; + var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value; + + Neo.painter.setColor(r<<16 | g<<8 | b); + Neo.updateUIColor(true, true); + } +}; + +Neo.ColorSlider.prototype.slide = function(x, y) { + var value; + if (x >= 0 && x < 60 && y >= 0 && y <= 15) { + var v = Math.floor((x - 5) * 5.0); + value = Math.round(v / 5) * 5; + + this.value0 = value; + this.x0 = x; + + } else { + var d = (x - this.x0) / 3.0; + value = this.value0 + d; + } + + var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0; + this.value = Math.max(Math.min(value, 255), min); + + if (this.type == Neo.SLIDERTYPE_ALPHA) { + Neo.painter.alpha = this.value / 255.0; + this.update(); + Neo.updateUIColor(false, false); + + } else { + var r = Neo.sliders[Neo.SLIDERTYPE_RED].value; + var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value; + var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value; + + Neo.painter.setColor(r<<16 | g<<8 | b); +// Neo.updateUIColor(true, true); + } +}; + +Neo.ColorSlider.prototype.update = function() { + var color = Neo.painter.getColor(); + var alpha = Neo.painter.alpha * 255; + + switch (this.type) { + case Neo.SLIDERTYPE_RED: this.value = (color & 0x0000ff); break; + case Neo.SLIDERTYPE_GREEN: this.value = (color & 0x00ff00) >> 8; break; + case Neo.SLIDERTYPE_BLUE: this.value = (color & 0xff0000) >> 16; break; + case Neo.SLIDERTYPE_ALPHA: this.value = alpha; break; + } + + var width = this.value * 49.0 / 255.0; + width = Math.max(Math.min(48, width), 1); + + this.slider.style.width = width.toFixed(2) + "px"; + this.label.innerHTML = this.prefix + this.value.toFixed(0); +}; + +/* +------------------------------------------------------------------------- + SizeSlider +------------------------------------------------------------------------- +*/ + +Neo.SizeSlider = function() {}; + +Neo.SizeSlider.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.isMouseDown = false; + this.value = this.value0 = 1; + + this.element.className = "sizeSlider"; + this.element.innerHTML = "<div class='slider'></div><div class='label'></div>"; + this.element.innerHTML += "<div class='hit'></div>" + + this.slider = this.element.getElementsByClassName('slider')[0]; + this.label = this.element.getElementsByClassName('label')[0]; + this.hit = this.element.getElementsByClassName('hit')[0]; + this.hit['data-slider'] = params.type; + + this.slider.style.backgroundColor = Neo.painter.foregroundColor; + this.update(); + return this; +}; + +Neo.SizeSlider.prototype.downHandler = function(x, y) { + if (Neo.painter.isShiftDown) { + this.shift(x, y); + + } else { + this.value0 = this.value; + this.y0 = y; + this.slide(x, y); + } +}; + +Neo.SizeSlider.prototype.moveHandler = function(x, y) { + this.slide(x, y); +}; + +Neo.SizeSlider.prototype.upHandler = function(x, y) { +}; + +Neo.SizeSlider.prototype.shift = function(x, y) { + var value0 = Neo.painter.lineWidth; + var value; + + if (!Neo.painter.tool.alt) { + var v = Math.floor((y - 4) * 30.0 / 33.0); + + value = Math.max(Math.min(v, 30), 1); + if (value0 > value || value0 == 30) { + value0--; + } else { + value0++; + } + this.setSize(value0); + } +}; + +Neo.SizeSlider.prototype.slide = function(x, y) { + var value; + if (!Neo.painter.tool.alt) { + if (x >= 0 && x < 48 && y >= 0 && y < 41) { + var v = Math.floor((y - 4) * 30.0 / 33.0); + value = v; + + this.value0 = value; + this.y0 = y; + + } else { + var d = (y - this.y0) / 7.0; + value = this.value0 + d; + } + } else { + // Ctrl+Alt+ドラッグでサイズ変更するとき + var d = y - this.y0; + value = this.value0 + d; + } + + value = Math.max(Math.min(value, 30), 1); + this.setSize(value); +}; + +Neo.SizeSlider.prototype.setSize = function(value) { + value = Math.round(value); + Neo.painter.lineWidth = Math.max(Math.min(30, value), 1); + + var tool = Neo.painter.getCurrentTool(); + if (tool) { + if (tool.type == Neo.Painter.TOOLTYPE_BRUSH) { + Neo.painter.alpha = tool.getAlpha(); + Neo.sliders[Neo.SLIDERTYPE_ALPHA].update(); + + } else if (tool.type == Neo.Painter.TOOLTYPE_TEXT) { + Neo.painter.updateInputText(); + } + } + this.update(); +}; + +Neo.SizeSlider.prototype.update = function() { + this.value = Neo.painter.lineWidth; + + var height = this.value * 33.0 / 30.0; + height = Math.max(Math.min(34, height), 1); + + this.slider.style.height = height.toFixed(2) + "px"; + this.label.innerHTML = this.value + "px"; + this.slider.style.backgroundColor = Neo.painter.foregroundColor; +}; + +/* +------------------------------------------------------------------------- + LayerControl +------------------------------------------------------------------------- +*/ + +Neo.LayerControl = function() {}; +Neo.LayerControl.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.isMouseDown = false; + + var ref = this; + + var mousedown = (window.PointerEvent) ? "onpointerdown" : "onmousedown"; + this.element[mousedown] = function(e) { ref._mouseDownHandler(e); } + this.element.className = "layerControl"; + this.element.innerHTML = "<div class='bg'></div><div class='label0'>Capa0</div><div class='label1'>Capa1</div><div class='line1'></div><div class='line0'></div>"; + + this.bg = this.element.getElementsByClassName('bg')[0]; + this.label0 = this.element.getElementsByClassName('label0')[0]; + this.label1 = this.element.getElementsByClassName('label1')[0]; + this.line0 = this.element.getElementsByClassName('line0')[0]; + this.line1 = this.element.getElementsByClassName('line1')[0]; + + this.line0.style.display = "none"; + this.line1.style.display = "none"; + this.label1.style.display = "none"; + + this.update(); + return this; +}; + +Neo.LayerControl.prototype._mouseDownHandler = function(e) { + if (e.button == 2 || e.ctrlKey || e.altKey) { + var visible = Neo.painter.visible[Neo.painter.current]; + Neo.painter.visible[Neo.painter.current] = (visible) ? false : true; + + } else { + var current = Neo.painter.current; + Neo.painter.current = (current) ? 0 : 1 + } + Neo.painter.updateDestCanvas(0, 0, Neo.painter.canvasWidth, Neo.painter.canvasHeight); + if (Neo.painter.tool.type == Neo.Painter.TOOLTYPE_PASTE) { + Neo.painter.tool.drawCursor(Neo.painter); + } + this.update(); + + if (this.onmousedown) this.onmousedown(this); +}; + +Neo.LayerControl.prototype.update = function() { + this.label0.style.display = (Neo.painter.current == 0) ? "block" : "none"; + this.label1.style.display = (Neo.painter.current == 1) ? "block" : "none"; + this.line0.style.display = (Neo.painter.visible[0]) ? "none" : "block"; + this.line1.style.display = (Neo.painter.visible[1]) ? "none" : "block"; +}; + +/* +------------------------------------------------------------------------- + ReserveControl +------------------------------------------------------------------------- +*/ +Neo.reserveControls = []; + +Neo.ReserveControl = function() {}; +Neo.ReserveControl.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + + var ref = this; + + var mousedown = (window.PointerEvent) ? "onpointerdown" : "onmousedown"; + this.element[mousedown] = function(e) { ref._mouseDownHandler(e); } + this.element.className = "reserve"; + + var index = parseInt(this.name.slice(7)) - 1; + this.element.style.top = "1px"; + this.element.style.left = (index * 15 + 2) + "px"; + + this.reserve = Neo.clone(Neo.config.reserves[index]); + this.update(); + + Neo.reserveControls.push(this); + return this; +}; + +Neo.ReserveControl.prototype._mouseDownHandler = function(e) { + if (e.button == 2 || e.ctrlKey || e.altKey) { + this.save(); + } else { + this.load(); + } + this.update(); +}; + +Neo.ReserveControl.prototype.load = function() { + Neo.painter.setToolByType(this.reserve.tool) + Neo.painter.foregroundColor = this.reserve.color; + Neo.painter.lineWidth = this.reserve.size; + Neo.painter.alpha = this.reserve.alpha; + + switch (this.reserve.tool) { + case Neo.Painter.TOOLTYPE_PEN: + case Neo.Painter.TOOLTYPE_BRUSH: + case Neo.Painter.TOOLTYPE_TONE: + Neo.painter.drawType = this.reserve.drawType; + }; + Neo.updateUI(); +}; + +Neo.ReserveControl.prototype.save = function() { + this.reserve.color = Neo.painter.foregroundColor; + this.reserve.size = Neo.painter.lineWidth; + this.reserve.drawType = Neo.painter.drawType; + this.reserve.alpha = Neo.painter.alpha; + this.reserve.tool = Neo.painter.tool.getType(); + this.element.style.backgroundColor = this.reserve.color; + this.update(); + Neo.updateUI(); +}; + +Neo.ReserveControl.prototype.update = function() { + this.element.style.backgroundColor = this.reserve.color; +}; + +/* +------------------------------------------------------------------------- + ScrollBarButton +------------------------------------------------------------------------- +*/ + +Neo.scrollH; +Neo.scrollV; + +Neo.ScrollBarButton = function() {}; +Neo.ScrollBarButton.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + + this.element.innerHTML = "<div></div>"; + this.barButton = this.element.getElementsByTagName("div")[0]; + this.element['data-bar'] = true; + this.barButton['data-bar'] = true; + + if (name == "scrollH") Neo.scrollH = this; + if (name == "scrollV") Neo.scrollV = this; + return this; +}; + +Neo.ScrollBarButton.prototype.update = function(oe) { + if (this.name == "scrollH") { + var a = oe.destCanvas.width / (oe.canvasWidth * oe.zoom); + var barWidth = Math.ceil(oe.destCanvas.width * a); + var barX = (oe.scrollBarX) * (oe.destCanvas.width - barWidth); + this.barButton.style.width = (Math.ceil(barWidth) - 4) + "px"; + this.barButton.style.left = Math.floor(barX) + "px"; + + } else { + var a = oe.destCanvas.height / (oe.canvasHeight * oe.zoom); + var barHeight = Math.ceil(oe.destCanvas.height * a); + var barY = (oe.scrollBarY) * (oe.destCanvas.height - barHeight); + this.barButton.style.height = (Math.ceil(barHeight) - 4) + "px"; + this.barButton.style.top = Math.floor(barY) + "px"; + } +}; + diff --git a/static/js/paintbbs/PaintBBS-1.3.4.css b/static/js/paintbbs/PaintBBS-1.3.4.css new file mode 100644 index 0000000..2e5b4f7 --- /dev/null +++ b/static/js/paintbbs/PaintBBS-1.3.4.css @@ -0,0 +1,547 @@ +.NEO { + margin:0; + line-height:18px; + + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + + touch-callout: none; + -webkit-touch-callout: none; +} + +.NEO *:active, +.NEO *:hover { + cursor: default; +} + +.NEO #container{ + width: 100%; + height: 100%; + position: relative; + border: 1px dotted transparent; +} + +.NEO #center{ + display: table; + position: relative; + height: 100%; + margin: auto; +} + +.NEO #toolsWrapper{ + width: 52px; + display: table; + position:absolute; + top: 0; + right: -3px; +} + +.NEO #tools{ + width: 52px; + display: table-cell; + vertical-align: middle; + position: relative; +} + +.NEO #painterContainer{ + display:table-cell; + vertical-align: middle; + position: relative; +} + +.NEO #painterWrapper{ + padding: 0 55px 0 0; + position: relative; + + float: right; /* なぜかChrome55でずれるので対策 */ +} + +.NEO #upper { + position: absolute; + right: 0; + + height:30px; + padding-right: 75px; //20px; + text-align:right; +} + +.NEO #lower { + height:30px; +} + +.NEO #painter { + position: relative; + padding: 20px 20px 20px 20px; + + margin-top: 30px; +} + +.NEO #canvas { + position: relative; + width: 300px; + height: 300px; + background-color: white; +} + +.NEO #headerButtons { + position: absolute; + top: 5px; + left: 5px; +} + +.NEO #footerButtons { + position: absolute; + bottom: 5px; + left: 5px; +} + +.NEO #window { float: left; } + +/* +----------------------- + Modal Window +----------------------- +*/ + +.NEO #pageView{ + background-color: white; +} + +.NEO #windowView{ + z-index: 9999; + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: white; +} + +/* +----------------------- + Controls +----------------------- +*/ + +.NEO #zoomMinus { + padding: 0; + margin: 0; + width:16px; + height:16px; + margin-left:1px; +} + +.NEO #zoomPlus { + padding: 0; + margin: 0; + width:16px; + height:16px; +} + +.NEO #zoomMinusWrapper { + position: absolute; + right: -20px; + bottom: -21px; + width: 19px; + height: 19px; + text-align:center; +} + +.NEO #zoomPlusWrapper { + position: absolute; + left: -21px; + bottom: -21px; + width: 19px; + height: 19px; + text-overflow: hidden; + text-align:center; +} + +.NEO #scrollH { + position: absolute; + left: 1px; + bottom: -20px; + width: calc(100% - 2px); + height: 18px; +} + +.NEO #scrollV { + position: absolute; + right: -20px; + top: 1px; + width: 18px; + height: calc(100% - 2px); +} + +.NEO #scrollH div { + position: absolute; + width: 50px; + height: 16px; +} + +.NEO #scrollV div { + position: absolute; + width: 16px; + height: 50px; +} + +.NEO #scrollH div:hover {} +.NEO #scrollV div:hover {} + +.NEO #neoWarning { + position: absolute; + left: 5px; + top: 5px; + color: red; + pointer-events: none; + text-align: left; + transition: all 2s; +} + +/* +----------------------- + Widgets +----------------------- +*/ + +.NEO .buttonOff { + display: inline-block; + border: 1px solid white; + height: 19px; + padding: 3px; + height: 16px; + font-size: 15px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + margin-right: 4px; + + border-left: 1px solid rgba(0, 0, 0, 0); + border-top: 1px solid rgba(0, 0, 0, 0); + border-right: 1px solid rgba(0, 0, 0, 0); + border-bottom: 1px solid rgba(0, 0, 0, 0); + + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + margin: 1px; + +} + +.NEO .buttonOff:hover {} + +.NEO .buttonOff:active, +.NEO .buttonOn { + display: inline-block; + height: 19px; + padding: 3px; + height: 16px; + font-size: 15px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + margin-right: 4px; + + border-right: 1px solid rgba(0, 0, 0, 0); + border-bottom: 1px solid rgba(0, 0, 0, 0); + + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + margin: 1px; +} + +.NEO #right { display: inline-block; float: right; margin-left: 10px; } + +.NEO .toolTipOff, +.NEO .toolTipFixed { + position:relative; + padding: 0; + margin: 0; + margin-top: 3px; + margin-bottom: 3px; + + width: 46px; + height: 18px; + border-top: 1px solid #ffffff; + border-left: 1px solid #ffffff; + border-right: 1px solid #9397b2; + border-bottom: 1px solid #9397b2; +} + +.NEO .toolTipOn { + position:relative; + padding: 0; + margin: 0; + margin-top: 3px; + margin-bottom: 3px; + + width: 46px; + height: 18px; + border-top: 1px solid rgba(0, 0, 0, 0); + border-left: 1px solid rgba(0, 0, 0, 0); + border-right: 1px solid #ffffff; + border-bottom: 1px solid #ffffff; +} + + + +.NEO .toolTipOff canvas, +.NEO .toolTipOn canvas, +.NEO .toolTipFixed canvas { + position: absolute; + top: 0; + left: 0; +} + +.NEO .toolTipOff .label, +.NEO .toolTipOn .label, +.NEO .toolTipFixed .label { + position: absolute; + bottom: -4px; + left: 1px; + font-size:12px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: -1px; + overflow: hidden !important; +} + +.NEO .colorTips { + position:relative; + width: 48px; + height: 144px; + padding: 0; + margin: 0; + margin-top: 4px; + margin-left: 0px; +} + +.NEO .colorTipOff { + position: absolute; + overflow: hidden; + width: 22px; + height: 18px; + margin: -1px 4px 0px 0px; + padding: 0; +} + +.NEO .colorTipOff img { + left: 0; + opacity: 0.5; + position: absolute; + pointer-events:none; +} + +.NEO .colorTipOn { + position: absolute; + overflow: hidden; + width: 22px; + height: 18px; + margin: -1px 4px 0px 0px; + padding: 0; +} + +.NEO .colorTipOn img { + left: -22px; + opacity: 0.5; + position: absolute; + pointer-events:none; +} + +.NEO .colorSlider { + width: 48px; + height:13px; + position: relative; + margin-top: 3px; +} + +.NEO .colorSlider .label { + pointer-events: none; + position: absolute; + left: 2px; + bottom: -3px; + font-size:12px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: middle; +} + +.NEO .colorSlider .slider { + position: absolute; + height: 100%; + left: 0px; + width: 50%; + background-color: #fa9696; + box-shadow: -1px 0 0 0px rgba(0, 0, 0, 0.3) inset; +} + +.NEO .colorSlider .hit { + position:absolute; + width: 60px; + height: 13px; + left: -6px; + background-color: white; + opacity: 0.01; +} + +.NEO .sizeSlider { + width: 48px; + height:33px; + position: relative; + margin-top: 4px; +} + +.NEO .sizeSlider .label { + pointer-events: none; + position: absolute; + left: 2px; + bottom: -3px; + font-size:12px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: middle; +} + +.NEO .sizeSlider .slider { + position: absolute; + width: 100%; + top: 0px; + height: 33%; + background-color: #82f238; + box-shadow: 0 -1px 0 0px rgba(0, 0, 0, 0.3) inset; +} + +.NEO .sizeSlider .hit { + position:absolute; + width: 48px; + height: 41px; + top: -4px; + background-color: white; + opacity: 0.01; +} + +.NEO .reserveControl { + width: 48px; + height: 13px; + position: relative; +} + +.NEO .reserveControl .reserve { + position: absolute; + width: 11px; + height: 8px; + background-color: white; +} + +.NEO .layerControl { + width: 48px; + height: 20px; + position: relative; + margin-top: 6px; +} + +.NEO .layerControl .bg { + position: absolute; + width: 44px; + height: 9px; + margin: 0; + + top: 0px; + left: 2px; +} + +.NEO .layerControl .line1 { + position: absolute; + width: 50px; + height:10px; + margin: 0; + padding: 0; + + top: 0px; + left: -1px; + background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent); +} + +.NEO .layerControl .line0 { + position: absolute; + width: 50px; + height: 10px; + margin: 0; + padding: 0; + + top: 10px; + left: -1px; + background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent); +} + +.NEO .layerControl .label1 { + position: absolute; + left: 2px; + Top: -4px; + font-size:11px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: baseline; +} + +.NEO .layerControl .label0 { + position: absolute; + left: 2px; + Top: 6px; + font-size:11px; + font-weight: 100; + font-family: 'Arial'; + letter-spacing: 0; + vertical-align: baseline; +} + +/* +----------------------- + InputText +----------------------- +*/ + +.NEO .inputText { + z-index: 100000; + position: absolute; + + text-align: left; + white-space: nowrap; + color: #0000ff; + + font-family: 'Arial'; + padding: 1px 5px 1px 5px; + font-size: 32px; + + line-height: 40px; + height: 40px; + min-width: 10em; + + bottom: 0px; + left: 250px; + + border: 1px solid #aaa; + background-color: white; +} + +*[contenteditable] { + user-select: auto !important; + -webkit-user-select: auto !important; + -moz-user-select: auto !important; +} + +#testtext { + user-select: auto !important; + -webkit-user-select: auto !important; + -moz-user-select: auto; +} + +[contenteditable="true"]:focus { + outline: 1px solid #b1d6fd; + border: 1px solid #b1d6fd; +} + diff --git a/static/js/paintbbs/PaintBBS-1.3.4.js b/static/js/paintbbs/PaintBBS-1.3.4.js new file mode 100644 index 0000000..8450a49 --- /dev/null +++ b/static/js/paintbbs/PaintBBS-1.3.4.js @@ -0,0 +1,6171 @@ +'use strict'; + +document.addEventListener("DOMContentLoaded", function() { + Neo.init(); + + if (!navigator.userAgent.match("Electron")) { + Neo.start(); + } +}); + + +var Neo = function() {}; + +Neo.version = "1.3.4"; +Neo.painter; +Neo.fullScreen = false; +Neo.uploaded = false; + +Neo.config = { + width: 300, + height: 300, + + colors: [ + "#000000", "#FFFFFF", + "#B47575", "#888888", + "#FA9696", "#C096C0", + "#FFB6FF", "#8080FF", + "#25C7C9", "#E7E58D", + "#E7962D", "#99CB7B", + "#FCECE2", "#F9DDCF" + ] +}; + +Neo.reservePen = {}; +Neo.reserveEraser = {}; + +Neo.SLIDERTYPE_RED = 0; +Neo.SLIDERTYPE_GREEN = 1; +Neo.SLIDERTYPE_BLUE = 2; +Neo.SLIDERTYPE_ALPHA = 3; +Neo.SLIDERTYPE_SIZE = 4; + +document.neo = Neo; + +Neo.init = function() { + var applets = document.getElementsByTagName('applet'); + if (applets.length == 0) { + applets = document.getElementsByTagName('applet-dummy'); + } + + for (var i = 0; i < applets.length; i++) { + var applet = applets[i]; + var name = applet.attributes.name.value; + if (name == "paintbbs") { + Neo.applet = applet; + Neo.initConfig(applet); + Neo.createContainer(applet); + Neo.init2(); + } + } +}; + +Neo.init2 = function() { + var pageview = document.getElementById("pageView"); + pageview.style.width = Neo.config.applet_width + "px"; + pageview.style.height = Neo.config.applet_height + "px"; + + Neo.canvas = document.getElementById("canvas"); + Neo.container = document.getElementById("container"); + Neo.toolsWrapper = document.getElementById("toolsWrapper"); + + Neo.painter = new Neo.Painter(); + Neo.painter.build(Neo.canvas, Neo.config.width, Neo.config.height); + + Neo.container.oncontextmenu = function() {return false;}; + + // 続きから描く + if (Neo.config.image_canvas) { + Neo.painter.loadImage(Neo.config.image_canvas); + } + + // 描きかけの画像が見つかったとき + Neo.storage = (Neo.isMobile()) ? localStorage : sessionStorage; + if (Neo.storage.getItem('timestamp')) { + setTimeout(function () { + if (confirm(Neo.translate("以前の編集データを復元しますか?"))) { + Neo.painter.loadSession(); + } + }, 1); + } + + window.addEventListener("pagehide", function(e) { + if (!Neo.uploaded) { + Neo.painter.saveSession(); + } else { + Neo.painter.clearSession(); + } + }, false); +} + +Neo.initConfig = function(applet) { + if (applet) { + var name = applet.attributes.name.value || "neo"; + var appletWidth = applet.attributes.width; + var appletHeight = applet.attributes.height; + if (appletWidth) Neo.config.applet_width = parseInt(appletWidth.value); + if (appletHeight) Neo.config.applet_height = parseInt(appletHeight.value); + + var params = applet.getElementsByTagName('param'); + for (var i = 0; i < params.length; i++) { + var p = params[i]; + Neo.config[p.name] = Neo.fixConfig(p.value); + + if (p.name == "image_width") Neo.config.width = parseInt(p.value); + if (p.name == "image_height") Neo.config.height = parseInt(p.value); + } + + var emulationMode = Neo.config.neo_emulation_mode || "2.22_8x"; + Neo.config.neo_alt_translation = emulationMode.slice(-1).match(/x/i); + + Neo.readStyles(); + Neo.applyStyle("color_bk", "#ccccff"); + Neo.applyStyle("color_bk2", "#bbbbff"); + Neo.applyStyle("color_tool_icon", "#e8dfae"); + Neo.applyStyle("color_icon", "#ccccff"); + Neo.applyStyle("color_iconselect", "#ffaaaa"); + Neo.applyStyle("color_text", "#666699"); + Neo.applyStyle("color_bar", "#6f6fae"); + Neo.applyStyle("tool_color_button", "#e8dfae"); + Neo.applyStyle("tool_color_button2", "#f8daaa"); + Neo.applyStyle("tool_color_text", "#773333"); + Neo.applyStyle("tool_color_bar", "#ddddff"); + Neo.applyStyle("tool_color_frame", "#000000"); + + var e = document.getElementById("container"); + Neo.config.inherit_color = Neo.getInheritColor(e); + if (!Neo.config.color_frame) Neo.config.color_frame = Neo.config.color_text; + } + + Neo.config.reserves = [ + { size:1, + color:"#000000", alpha:1.0, + tool:Neo.Painter.TOOLTYPE_PEN, + drawType:Neo.Painter.DRAWTYPE_FREEHAND + }, + { size:5, + color:"#FFFFFF", alpha:1.0, + tool:Neo.Painter.TOOLTYPE_ERASER, + drawType:Neo.Painter.DRAWTYPE_FREEHAND + }, + { size:10, + color:"#FFFFFF", alpha:1.0, + tool:Neo.Painter.TOOLTYPE_ERASER, + drawType:Neo.Painter.DRAWTYPE_FREEHAND + }, + ]; + + Neo.reservePen = Neo.clone(Neo.config.reserves[0]); + Neo.reserveEraser = Neo.clone(Neo.config.reserves[1]); +}; + +Neo.fixConfig = function(value) { + // javaでは"#12345"を色として解釈するがjavascriptでは"#012345"に変換しないとだめ + if (value.match(/^#[0-9a-fA-F]{5}$/)) { + value = "#0" + value.slice(1); + } + return value; +}; + +Neo.initSkin = function() { + var sheet = document.styleSheets[0]; + if (!sheet) { + var style = document.createElement("style"); + document.head.appendChild(style); // must append before you can access sheet property + sheet = style.sheet; + } + + Neo.styleSheet = sheet; + + var lightBorder = Neo.multColor(Neo.config.color_icon, 1.3); + var darkBorder = Neo.multColor(Neo.config.color_icon, 0.7); + var lightBar = Neo.multColor(Neo.config.color_bar, 1.3); + var darkBar = Neo.multColor(Neo.config.color_bar, 0.7); + var bgImage = Neo.backgroundImage(); + + Neo.addRule(".NEO #container", "background-image", "url(" + bgImage + ")"); + Neo.addRule(".NEO .colorSlider .label", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .sizeSlider .label", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .layerControl .label1", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .layerControl .label0", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .toolTipOn .label", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .toolTipOff .label", "color", Neo.config.tool_color_text); + + Neo.addRule(".NEO #toolSet", "background-color", Neo.config.color_bk); + Neo.addRule(".NEO #tools", "color", Neo.config.tool_color_text); + Neo.addRule(".NEO .layerControl .bg", "border-bottom", "1px solid " + Neo.config.tool_color_text); + + Neo.addRule(".NEO .buttonOn", "color", Neo.config.color_text); + Neo.addRule(".NEO .buttonOff", "color", Neo.config.color_text); + + Neo.addRule(".NEO .buttonOff", "background-color", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff", "border-top", "1px solid ", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff", "border-left", "1px solid ", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff", "box-shadow", "0 0 0 1px " + Neo.config.color_icon + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO .buttonOff:hover", "background-color", Neo.config.color_icon); + Neo.addRule(".NEO .buttonOff:hover", "border-top", "1px solid " + lightBorder); + Neo.addRule(".NEO .buttonOff:hover", "border-left", "1px solid " + lightBorder); + Neo.addRule(".NEO .buttonOff:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "background-color", darkBorder); + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-top", "1px solid " + darkBorder); + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-left", "1px solid " + darkBorder); + Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame); + + + Neo.addRule(".NEO #canvas", "border", "1px solid " + Neo.config.color_frame); + Neo.addRule(".NEO #scrollH, .NEO #scrollV", "background-color", Neo.config.color_icon); + Neo.addRule(".NEO #scrollH, .NEO #scrollV", "box-shadow", "0 0 0 1px white" + ", 0 0 0 2px " + Neo.config.color_frame); + + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "background-color", Neo.config.color_bar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "box-shadow", "0 0 0 1px " + Neo.config.color_icon); + Neo.addRule(".NEO #scrollH div:hover, .NEO #scrollV div:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect); + + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-top", "1px solid " + lightBar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-left", "1px solid " + lightBar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-right", "1px solid " + darkBar); + Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-bottom", "1px solid " + darkBar); + + Neo.addRule(".NEO .toolTipOn", "background-color", Neo.multColor(Neo.config.tool_color_button, 0.7)); + Neo.addRule(".NEO .toolTipOff", "background-color", Neo.config.tool_color_button); + Neo.addRule(".NEO .toolTipFixed", "background-color", Neo.config.tool_color_button2); + + Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "background-color", Neo.config.tool_color_bar); + Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar); + Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar); + Neo.addRule(".NEO .layerControl", "background-color", Neo.config.tool_color_bar); + + Neo.addRule(".NEO .colorTipOn, .NEO .colorTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .toolTipOn, .NEO .toolTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .toolTipFixed", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .reserveControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .layerControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame); + Neo.addRule(".NEO .reserveControl .reserve", "border", "1px solid " + Neo.config.tool_color_frame); + + if (navigator.language.indexOf("ja") != 0) { + var labels = ["Fixed", "On", "Off"]; + for (var i = 0; i < labels.length; i++) { + var selector = ".NEO .toolTip" + labels[i] + " .label"; + Neo.addRule(selector, "letter-spacing", "0px !important"); + } + } +}; + +Neo.addRule = function(selector, styleName, value, sheet) { + if (!sheet) sheet = Neo.styleSheet; + if (sheet.addRule) { + sheet.addRule(selector, styleName + ":" + value, sheet.rules.length); + + } else if (sheet.insertRule) { + var rule = selector + "{" + styleName + ":" + value + "}"; + var index = sheet.cssRules.length; + sheet.insertRule(rule, index); + } +}; + +Neo.readStyles = function() { + Neo.rules = {}; + for (var i = 0; i < document.styleSheets.length; i++) { + Neo.readStyle(document.styleSheets[i]); + } +}; + +Neo.readStyle = function(sheet) { + try { + var rules = sheet.cssRules; + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if (rule.styleSheet) { + Neo.readStyle(rule.styleSheet); + continue; + } + + var selector = rule.selectorText + if (selector) { + selector = selector.replace(/^(.NEO\s+)?\./, '') + + var css = rule.cssText || rule.style.cssText; + var result = css.match(/color:\s*(.*)\s*;/) + if (result) { + var hex = Neo.colorNameToHex(result[1]); + if (hex) { + Neo.rules[selector] = hex; + } + } + } + } + } catch (e) {} +}; + +Neo.applyStyle = function(name, defaultColor) { + if (Neo.config[name] == undefined) { + Neo.config[name] = Neo.rules[name] || defaultColor; + } +}; + +Neo.getInheritColor = function(e) { + var result = "#000000"; + while (e && e.style) { + if (e.style.color != "") { + result = e.style.color; + break; + } + if (e.attributes["text"]) { + result = e.attributes["text"].value; + break; + } + e = e.parentNode; + } + return result; +}; + +Neo.backgroundImage = function() { + var c1 = Neo.painter.getColor(Neo.config.color_bk) | 0xff000000; + var c2 = Neo.painter.getColor(Neo.config.color_bk2) | 0xff000000; + var bgCanvas = document.createElement("canvas"); + bgCanvas.width = 16; + bgCanvas.height = 16; + var ctx = bgCanvas.getContext("2d"); + var imageData = ctx.getImageData(0, 0, 16, 16); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var index = 0; + for (var y = 0; y < 16; y++) { + for (var x = 0; x < 16; x++) { + buf32[index++] = (x == 14 || y == 14) ? c2 : c1; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + return bgCanvas.toDataURL('image/png'); +}; + +Neo.multColor = function(c, scale) { + var r = Math.round(parseInt(c.substr(1, 2), 16) * scale); + var g = Math.round(parseInt(c.substr(3, 2), 16) * scale); + var b = Math.round(parseInt(c.substr(5, 2), 16) * scale); + r = ("0" + Math.min(Math.max(r, 0), 255).toString(16)).substr(-2); + g = ("0" + Math.min(Math.max(g, 0), 255).toString(16)).substr(-2); + b = ("0" + Math.min(Math.max(b, 0), 255).toString(16)).substr(-2); + return '#' + r + g + b; +}; + +Neo.colorNameToHex = function(name) { + var colors = {"aliceblue":"#f0f8ff", "antiquewhite":"#faebd7", "aqua":"#00ffff","aquamarine":"#7fffd4", "azure":"#f0ffff", "beige":"#f5f5dc", "bisque":"#ffe4c4", "black":"#000000", "blanchedalmond":"#ffebcd", "blue":"#0000ff", "blueviolet":"#8a2be2", "brown":"#a52a2a", "burlywood":"#deb887", "cadetblue":"#5f9ea0", "chartreuse":"#7fff00", "chocolate":"#d2691e", "coral":"#ff7f50", "cornflowerblue":"#6495ed", "cornsilk":"#fff8dc", "crimson":"#dc143c", "cyan":"#00ffff", "darkblue":"#00008b", "darkcyan":"#008b8b", "darkgoldenrod":"#b8860b", "darkgray":"#a9a9a9", "darkgreen":"#006400", "darkkhaki":"#bdb76b", "darkmagenta":"#8b008b", "darkolivegreen":"#556b2f", "darkorange":"#ff8c00", "darkorchid":"#9932cc", "darkred":"#8b0000", "darksalmon":"#e9967a", "darkseagreen":"#8fbc8f", "darkslateblue":"#483d8b", "darkslategray":"#2f4f4f", "darkturquoise":"#00ced1", "darkviolet":"#9400d3", "deeppink":"#ff1493", "deepskyblue":"#00bfff", "dimgray":"#696969", "dodgerblue":"#1e90ff", "firebrick":"#b22222", "floralwhite":"#fffaf0", "forestgreen":"#228b22", "fuchsia":"#ff00ff", "gainsboro":"#dcdcdc", "ghostwhite":"#f8f8ff", "gold":"#ffd700", "goldenrod":"#daa520", "gray":"#808080", "green":"#008000", "greenyellow":"#adff2f", "honeydew":"#f0fff0", "hotpink":"#ff69b4", "indianred ":"#cd5c5c", "indigo":"#4b0082", "ivory":"#fffff0", "khaki":"#f0e68c", "lavender":"#e6e6fa", "lavenderblush":"#fff0f5", "lawngreen":"#7cfc00", "lemonchiffon":"#fffacd", "lightblue":"#add8e6", "lightcoral":"#f08080", "lightcyan":"#e0ffff", "lightgoldenrodyellow":"#fafad2", "lightgrey":"#d3d3d3", "lightgreen":"#90ee90", "lightpink":"#ffb6c1", "lightsalmon":"#ffa07a", "lightseagreen":"#20b2aa", "lightskyblue":"#87cefa", "lightslategray":"#778899", "lightsteelblue":"#b0c4de", "lightyellow":"#ffffe0", "lime":"#00ff00", "limegreen":"#32cd32", "linen":"#faf0e6", "magenta":"#ff00ff", "maroon":"#800000", "mediumaquamarine":"#66cdaa", "mediumblue":"#0000cd", "mediumorchid":"#ba55d3", "mediumpurple":"#9370d8", "mediumseagreen":"#3cb371", "mediumslateblue":"#7b68ee", "mediumspringgreen":"#00fa9a", "mediumturquoise":"#48d1cc", "mediumvioletred":"#c71585", "midnightblue":"#191970", "mintcream":"#f5fffa", "mistyrose":"#ffe4e1", "moccasin":"#ffe4b5", "navajowhite":"#ffdead", "navy":"#000080", "oldlace":"#fdf5e6", "olive":"#808000", "olivedrab":"#6b8e23", "orange":"#ffa500", "orangered":"#ff4500", "orchid":"#da70d6", "palegoldenrod":"#eee8aa", "palegreen":"#98fb98", "paleturquoise":"#afeeee", "palevioletred":"#d87093", "papayawhip":"#ffefd5", "peachpuff":"#ffdab9", "peru":"#cd853f", "pink":"#ffc0cb", "plum":"#dda0dd", "powderblue":"#b0e0e6", "purple":"#800080", "rebeccapurple":"#663399", "red":"#ff0000", "rosybrown":"#bc8f8f", "royalblue":"#4169e1", "saddlebrown":"#8b4513", "salmon":"#fa8072", "sandybrown":"#f4a460", "seagreen":"#2e8b57", "seashell":"#fff5ee", "sienna":"#a0522d", "silver":"#c0c0c0", "skyblue":"#87ceeb", "slateblue":"#6a5acd", "slategray":"#708090", "snow":"#fffafa", "springgreen":"#00ff7f", "steelblue":"#4682b4", "tan":"#d2b48c", "teal":"#008080", "thistle":"#d8bfd8", "tomato":"#ff6347", "turquoise":"#40e0d0", "violet":"#ee82ee", "wheat":"#f5deb3", "white":"#ffffff", "whitesmoke":"#f5f5f5", "yellow":"#ffff00", "yellowgreen":"#9acd32"}; + + var rgb = name.toLowerCase().match(/rgb\((.*),(.*),(.*)\)/); + if (rgb) { + var r = ("0" + parseInt(rgb[1]).toString(16)).slice(-2) + var g = ("0" + parseInt(rgb[2]).toString(16)).slice(-2) + var b = ("0" + parseInt(rgb[3]).toString(16)).slice(-2) + return "#" + r + g + b + } + + if (typeof colors[name.toLowerCase()] != 'undefined') { + return colors[name.toLowerCase()]; + } + return false; +}; + +Neo.initComponents = function() { + document.getElementById("copyright").innerHTML += "v" + Neo.version; + + // アプレットのborderの動作をエミュレート + if (navigator.userAgent.search("FireFox") > -1) { + var container = document.getElementById("container"); + container.addEventListener("mousedown", function(e) { + container.style.borderColor = Neo.config.inherit_color; + e.stopPropagation(); + }, false); + document.addEventListener("mousedown", function(e) { + container.style.borderColor = 'transparent'; + }, false); + } + + // ドラッグしたまま画面外に移動した時 + document.addEventListener("mouseup", function(e) { + if (Neo.painter && !Neo.painter.isContainer(e.target)) { + Neo.painter.cancelTool(e.target); + } + }, false); + + // 投稿に失敗する可能性があるときは警告を表示する + Neo.showWarning(); + + if (Neo.styleSheet) { + Neo.addRule("*", "user-select", "none"); + Neo.addRule("*", "-webkit-user-select", "none"); + Neo.addRule("*", "-ms-user-select", "none"); + } +} + +Neo.initButtons = function() { + new Neo.Button().init("undo").onmouseup = function() { + new Neo.UndoCommand(Neo.painter).execute(); + }; + new Neo.Button().init("redo").onmouseup = function () { + new Neo.RedoCommand(Neo.painter).execute(); + }; + new Neo.Button().init("window").onmouseup = function() { + new Neo.WindowCommand(Neo.painter).execute(); + }; + new Neo.Button().init("submit").onmouseup = function() { + new Neo.SubmitCommand(Neo.painter).execute(); + }; + new Neo.Button().init("copyright").onmouseup = function() { + new Neo.CopyrightCommand(Neo.painter).execute(); + }; + new Neo.Button().init("zoomPlus").onmouseup = function() { + new Neo.ZoomPlusCommand(Neo.painter).execute(); + }; + new Neo.Button().init("zoomMinus").onmouseup = function() { + new Neo.ZoomMinusCommand(Neo.painter).execute(); + }; + + Neo.fillButton = new Neo.FillButton().init("fill"); + Neo.rightButton = new Neo.RightButton().init("right"); + + if (Neo.isMobile()) { + Neo.rightButton.element.style.display = "block"; + } + + // toolTip + Neo.penTip = new Neo.PenTip().init("pen"); + Neo.pen2Tip = new Neo.Pen2Tip().init("pen2"); + Neo.effectTip = new Neo.EffectTip().init("effect"); + Neo.effect2Tip = new Neo.Effect2Tip().init("effect2"); + Neo.eraserTip = new Neo.EraserTip().init("eraser"); + Neo.drawTip = new Neo.DrawTip().init("draw"); + Neo.maskTip = new Neo.MaskTip().init("mask"); + + Neo.toolButtons = [Neo.fillButton, + Neo.penTip, + Neo.pen2Tip, + Neo.effectTip, + Neo.effect2Tip, + Neo.drawTip, + Neo.eraserTip]; + + // colorTip + for (var i = 1; i <= 14; i++) { + new Neo.ColorTip().init("color" + i, {index:i}); + }; + + // colorSlider + Neo.sliders[Neo.SLIDERTYPE_RED] = new Neo.ColorSlider().init( + "sliderRed", {type:Neo.SLIDERTYPE_RED}); + Neo.sliders[Neo.SLIDERTYPE_GREEN] = new Neo.ColorSlider().init( + "sliderGreen", {type:Neo.SLIDERTYPE_GREEN}); + Neo.sliders[Neo.SLIDERTYPE_BLUE] = new Neo.ColorSlider().init( + "sliderBlue", {type:Neo.SLIDERTYPE_BLUE}); + Neo.sliders[Neo.SLIDERTYPE_ALPHA] = new Neo.ColorSlider().init( + "sliderAlpha", {type:Neo.SLIDERTYPE_ALPHA}); + + // sizeSlider + Neo.sliders[Neo.SLIDERTYPE_SIZE] = new Neo.SizeSlider().init( + "sliderSize", {type:Neo.SLIDERTYPE_SIZE}); + + // reserveControl + for (var i = 1; i <= 3; i++) { + new Neo.ReserveControl().init("reserve" + i, {index:i}); + }; + + new Neo.LayerControl().init("layerControl"); + new Neo.ScrollBarButton().init("scrollH"); + new Neo.ScrollBarButton().init("scrollV"); +}; + +Neo.start = function(isApp) { + if (!Neo.painter) return; + + Neo.initSkin(); + Neo.initComponents(); + Neo.initButtons(); + + Neo.isApp = isApp; + if (Neo.applet) { + var name = Neo.applet.attributes.name.value || "paintbbs"; + Neo.applet.outerHTML = ""; + document[name] = Neo; + + Neo.resizeCanvas(); + Neo.container.style.visibility = "visible"; + + if (Neo.isApp) { + var ipc = require('electron').ipcRenderer; + ipc.sendToHost('neo-status', 'ok'); + + } else { + if (document.paintBBSCallback) { + document.paintBBSCallback('start'); + } + } + } +}; + +Neo.isIE = function() { + var ms = false; + if (/MSIE 10/i.test(navigator.userAgent)) { + ms = true; // This is internet explorer 10 + } + if (/MSIE 9/i.test(navigator.userAgent) || + /rv:11.0/i.test(navigator.userAgent)) { + ms = true; // This is internet explorer 9 or 11 + } + return ms +}; + +Neo.isMobile = function() { + return navigator.userAgent.match(/Android|iPhone|iPad|iPod/i); +}; + +Neo.showWarning = function() { + var futaba = location.hostname.match(/2chan.net/i); + var samplebbs = location.hostname.match(/neo.websozai.jp/i); + + var chrome = navigator.userAgent.match(/Chrome\/(\d+)/i); + if (chrome && chrome.length > 1) chrome = chrome[1]; + + var edge = navigator.userAgent.match(/Edge\/(\d+)/i); + if (edge && edge.length > 1) edge = edge[1]; + + var ms = Neo.isIE(); + + var str = ""; + if (futaba || samplebbs) { + if (ms || (edge && edge < 15)) { + str = Neo.translate("このブラウザでは<br>投稿に失敗することがあります<br>"); + } + } + + // もし<PARAM NAME="neo_warning" VALUE="...">があれば表示する + if (Neo.config.neo_warning) { + str += Neo.config.neo_warning; + } + + var warning = document.getElementById("neoWarning") + warning.innerHTML = str; + setTimeout(function() { warning.style.opacity = "0"; }, 15000); +}; + +/* + ----------------------------------------------------------------------- + UIの更新 + ----------------------------------------------------------------------- +*/ + +Neo.updateUI = function() { + var current = Neo.painter.tool.getToolButton(); + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + if (current) { + if (current == toolTip) { + toolTip.setSelected(true); + toolTip.update(); + } else { + toolTip.setSelected(false); + } + } + } + if (Neo.drawTip) { + Neo.drawTip.update(); + } + + Neo.updateUIColor(true, false); +} + +Neo.updateUIColor = function(updateSlider, updateColorTip) { + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + toolTip.update(); + } + + if (updateSlider) { + for (var i = 0; i < Neo.sliders.length; i++) { + var slider = Neo.sliders[i]; + slider.update(); + } + } + + // パレットを変更するとき + if (updateColorTip) { + var colorTip = Neo.ColorTip.getCurrent(); + if (colorTip) { + colorTip.setColor(Neo.painter.foregroundColor); + } + } +}; + +/* + ----------------------------------------------------------------------- + リサイズ対応 + ----------------------------------------------------------------------- +*/ + +Neo.updateWindow = function() { + if (Neo.fullScreen) { + document.getElementById("windowView").style.display = "block"; + document.getElementById("windowView").appendChild(Neo.container); + + } else { + document.getElementById("windowView").style.display = "none"; + document.getElementById("pageView").appendChild(Neo.container); + } + Neo.resizeCanvas(); +}; + +Neo.resizeCanvas = function() { + var appletWidth = Neo.container.clientWidth; + var appletHeight = Neo.container.clientHeight; + + var canvasWidth = Neo.painter.canvasWidth; + var canvasHeight = Neo.painter.canvasHeight; + + var width0 = canvasWidth * Neo.painter.zoom; + var height0 = canvasHeight * Neo.painter.zoom; + + var width = (width0 < appletWidth - 100) ? width0 : appletWidth - 100; + var height = (height0 < appletHeight - 120) ? height0 : appletHeight - 120; + + //width, heightは偶数でないと誤差が出るため + width = Math.floor(width / 2) * 2; + height = Math.floor(height / 2) * 2; + + Neo.painter.destWidth = width; + Neo.painter.destHeight = height; + + Neo.painter.destCanvas.width = width; + Neo.painter.destCanvas.height = height; + Neo.painter.destCanvasCtx = Neo.painter.destCanvas.getContext("2d"); + Neo.painter.destCanvasCtx.imageSmoothingEnabled = false; + Neo.painter.destCanvasCtx.mozImageSmoothingEnabled = false; + + Neo.canvas.style.width = width + "px"; + Neo.canvas.style.height = height + "px"; + + var top = (Neo.container.clientHeight - toolsWrapper.clientHeight) / 2; + Neo.toolsWrapper.style.top = ((top > 0) ? top : 0) + "px"; + + if (top < 0) { + var s = Neo.container.clientHeight / toolsWrapper.clientHeight; + Neo.toolsWrapper.style.transform = + "translate(0, " + top + "px) scale(1," + s + ")"; + } else { + Neo.toolsWrapper.style.transform = ""; + } + + Neo.painter.setZoom(Neo.painter.zoom); + Neo.painter.updateDestCanvas(0, 0, canvasWidth, canvasHeight); +}; + +/* + ----------------------------------------------------------------------- + 投稿 + ----------------------------------------------------------------------- +*/ + +Neo.clone = function(src) { + var dst = {}; + for (var k in src) { + dst[k] = src[k]; + } + return dst; +}; + +Neo.getSizeString = function(len) { + var result = String(len); + while (result.length < 8) { + result = "0" + result; + } + return result; +}; + +Neo.openURL = function(url) { + if (Neo.isApp) { + require('electron').shell.openExternal(url); + + } else { + window.open(url, '_blank'); + } +}; + +Neo.submit = function(board, blob, thumbnail, thumbnail2) { + var url = Neo.config.url_save; + var headerString = Neo.str_header || ""; + console.log("submit url=" + url + " header=" + headerString); + + if (document.paintBBSCallback) { + var result = document.paintBBSCallback('check') + if (result == 0 || result == "false") { + return; + } + + result = document.paintBBSCallback('header') + if (result && typeof result == "string") { + headerString == result; + } + } + if (!headerString) headerString = Neo.config.send_header || ""; + + var imageType = Neo.config.send_header_image_type; + if (imageType && imageType == "true") { + headerString = "image_type=png&" + headerString + console.log("header=" + headerString); + } + + var header = new Blob([headerString]); + var headerLength = this.getSizeString(header.size); + var imgLength = this.getSizeString(blob.size); + + var array = ['P', // PaintBBS + headerLength, + header, + imgLength, + '\r\n', + blob]; + + if (thumbnail) { + var thumbnailLength = this.getSizeString(thumbnail.size); + array.push(thumbnailLength, thumbnail); + } + if (thumbnail2) { + var thumbnail2Length = this.getSizeString(thumbnail2.size); + array.push(thumbnail2Length, thumbnail2); + } + + var body = new Blob(array, {type: 'application/octet-binary'}); //これが必要!! + + var request = new XMLHttpRequest(); + request.open("POST", url, true); + + request.onload = function(e) { + console.log(request.response); + Neo.uploaded = true; + + /*var url = Neo.config.url_exit; + if (url[0] == '/') { + url = url.replace(/^.*\//, ''); //よくわかんないけどとりあえず + } + + // ふたばのpaintpost.phpは、画像投稿に成功するとresponseに + // "./futaba.php?mode=paintcom&painttmp=.png" + // という文字列を返します。 + // + // NEOでは、responseに文字列"painttmp="が含まれる場合は + // <PARAM>で指定されたurl_exitを無視して、このURLにジャンプします。 + var responseURL = request.response.replace(/&/g, '&'); + if (responseURL.match(/painttmp=/)) { + url = responseURL; + } + var exitURL = url; + + // しぃちゃんのドキュメントをよく見たら + // responseが "URL:〜" の形だった場合はそこへ飛ばすって書いてありました。 + // こっちを使うべきでした…… + if (responseURL.match(/^URL:/)) { + exitURL = responseURL.replace(/^URL:/, ''); + } + + location.href = exitURL;*/ + location.href = Neo.config.url_exit; + }; + request.onerror = function(e) { + console.log("error"); + }; + request.onabort = function(e) { + console.log("abort"); + }; + request.ontimeout = function(e) { + console.log("timeout"); + }; + + request.send(body); +}; + +/* + ----------------------------------------------------------------------- + LiveConnect + ----------------------------------------------------------------------- +*/ + +Neo.getColors = function() { + console.log("getColors") + console.log("defaultColors==", Neo.config.colors.join('\n')); + var array = [] + for (var i = 0; i < 14; i++) { + array.push(Neo.colorTips[i].color) + } + return array.join('\n'); + // return Neo.config.colors.join('\n'); +}; + +Neo.setColors = function(colors) { + console.log("setColors"); + var array = colors.split('\n'); + for (var i = 0; i < 14; i++) { + var color = array[i]; + Neo.config.colors[i] = color; + Neo.colorTips[i].setColor(color); + } +}; + + +Neo.pExit = function() { + new Neo.SubmitCommand(Neo.painter).execute(); +}; + +Neo.str_header = ""; + +/* + ----------------------------------------------------------------------- + DOMツリーの作成 + ----------------------------------------------------------------------- +*/ + +Neo.createContainer = function(applet) { + var neo = document.createElement("div"); + neo.className = "NEO"; + neo.id = "NEO"; + var html = (function() {/* + +<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> + +<div id="pageView" style="width:450px; height:470px; margin:auto;"> +<div id="container" style="visibility:hidden;" class="o"> +<div id="center" class="o"> +<div id="painterContainer" class="o"> +<div id="painterWrapper" class="o"> +<div id="upper" class="o"> +<div id="redo">[やり直し]</div> +<div id="undo">[元に戻す]</div> +<div id="fill">[塗り潰し]</div> +<div id="right" style="display:none;">[右]</div> +</div> +<div id="painter"> +<div id="canvas"> <!-- class="o">--> +<div id="scrollH"></div> +<div id="scrollV"></div> +<div id="zoomPlusWrapper"> +<div id="zoomPlus">+</div> +</div> +<div id="zoomMinusWrapper"> +<div id="zoomMinus">-</div> +</div> +<div id="neoWarning"></div> +</div> +</div> +<div id="lower" class="o"> +</div> +</div> +<div id="toolsWrapper"> +<div id="tools"> +<div id="toolSet"> +<div id="pen"></div> +<div id="pen2"></div> +<div id="effect"></div> +<div id="effect2"></div> +<div id="eraser"></div> +<div id="draw"></div> +<div id="mask"></div> + +<div class="colorTips"> +<div id="color2"></div><div id="color1"></div><br> +<div id="color4"></div><div id="color3"></div><br> +<div id="color6"></div><div id="color5"></div><br> +<div id="color8"></div><div id="color7"></div><br> +<div id="color10"></div><div id="color9"></div><br> +<div id="color12"></div><div id="color11"></div><br> +<div id="color14"></div><div id="color13"></div> +</div> + +<div id="sliderRed"></div> +<div id="sliderGreen"></div> +<div id="sliderBlue"></div> +<div id="sliderAlpha"></div> +<div id="sliderSize"></div> + +<div class="reserveControl" style="margin-top:4px;"> +<div id="reserve1"></div> +<div id="reserve2"></div> +<div id="reserve3"></div> +</div> +<div id="layerControl" style="margin-top:6px;"></div> + +<!--<div id="toolPad" style="height:20px;"></div>--> +</div> +</div> +</div> +</div> +</div> +<div id="headerButtons"> +<div id="window">[窓]</div> +</div> +<div id="footerButtons"> +<div id="submit">[投稿]</div> +<div id="copyright">[(C)しぃちゃん PaintBBS NEO]</div> +</div> +</div> +</div> + +<div id="windowView" style="display: none;"> + +</div> + + + */}).toString().match(/\/\*([^]*)\*\//)[1]; + + neo.innerHTML = html.replace(/\[(.*?)\]/g, function(match, str) { + return Neo.translate(str) + }) + + var parent = applet.parentNode; + parent.appendChild(neo); + parent.insertBefore(neo, applet); + + // applet.style.display = "none"; + + // NEOを組み込んだURLをアプリ版で開くとDOMツリーが2重にできて格好悪いので消しておく + setTimeout(function() { + var tmp = document.getElementsByClassName("NEO"); + if (tmp.length > 1) { + for (var i = 1; i < tmp.length; i++) { + tmp[i].style.display = "none"; + } + } + }, 0); +}; + + +'use strict'; + +Neo.dictionary = { + "ja": {}, + "en": { + "やり直し": "Redo", + "元に戻す": "Undo", + "塗り潰し": "Paint", + "窓": "F ", + "投稿": "Send", + "(C)しぃちゃん PaintBBS NEO": "(C)shi-chan PaintBBS NEO", + "鉛筆": "Solid", + "水彩": "WaterC", + "テキスト": "Text", + "トーン": "Tone", + "ぼかし": "ShadeOff", + "覆い焼き": "HLight", + "焼き込み": "Dark", + "消しペン": "White", + "消し四角": "WhiteRect", + "全消し": "Clear", + "四角": "Rect", + "線四角": "LineRect", + "楕円": "Oval", + "線楕円": "LineOval", + "コピー": "Copy", + "レイヤ結合": "lay-unif", + "角取り": "Antialias", + "左右反転": "reverseL", + "上下反転": "reverseU", + "傾け": "lie", + "通常": "Normal", + "マスク": "Mask", + "逆マスク": "ReMask", + "加算": "And", + "逆加算": "Div", + "手書き": "FreeLine", + "直線": "Straight", + "BZ曲線": "Bezie", + "ページビュー?": "Page view?", + "ウィンドウビュー?": "Window view?", + "以前の編集データを復元しますか?": "Restore session?", + "右": "Right Click", + + "PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?": "PaintBBS NEO is an HTML5 port of Oekaki Shi-BBS PaintBBS (©2000-2004 shi-chan). Show the project page?", + "このブラウザでは<br>投稿に失敗することがあります<br>": "This browser may fail to send your picture.<br>", + }, + "enx": { + "やり直し": "Redo", + "元に戻す": "Undo", + "塗り潰し": "Fill", + "窓": "Float", + "投稿": "Send", + "(C)しぃちゃん PaintBBS NEO": "©shi-cyan PaintBBS NEO", + "鉛筆": "Solid", + "水彩": "WaterCo", + "テキスト": "Text", + "トーン": "Halftone", + "ぼかし": "Blur", + "覆い焼き": "Light", + "焼き込み": "Dark", + "消しペン": "White", + "消し四角": "WhiteRe", + "全消し": "Clear", + "四角": "Rect", + "線四角": "LineRect", + "楕円": "Oval", + "線楕円": "LineOval", + "コピー": "Copy", + "レイヤ結合": "layerUnit", + "角取り": "antiAlias", + "左右反転": "flipHorita", + "上下反転": "flipVertic", + "傾け": "rotate", + "通常": "Normal", + "マスク": "Mask", + "逆マスク": "ReMask", + "加算": "And", + "逆加算": "Divide", + "手書き": "Freehan", + "直線": "Line", + "BZ曲線": "Bezier", + "Layer0": "LayerBG", + "Layer1": "LayerFG", + "ページビュー?": "Page view?", + "ウィンドウビュー?": "Window view?", + "以前の編集データを復元しますか?": "Restore session?", + "右": "Right Click", + + "PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?": "PaintBBS NEO is an HTML5 port of Oekaki Shi-BBS PaintBBS (©2000-2004 shi-chan). Show the project page?", + "このブラウザでは<br>投稿に失敗することがあります<br>": "This browser may fail to send your picture.<br>", + }, + "es": { + "やり直し": "Rehacer", + "元に戻す": "Deshacer", + "塗り潰し": "Llenar", + "窓": "Ventana", + "投稿": "Enviar", + "(C)しぃちゃん PaintBBS NEO": "©shi-cyan PaintBBS NEO", + "鉛筆": "Lápiz", + "水彩": "Acuarela", + "テキスト": "Texto", + "トーン": "Tono", + "ぼかし": "Gradación", + "覆い焼き": "Sobreexp.", + "焼き込み": "Quemar", + "消しペン": "Goma", + "消し四角": "GomaRect", + "全消し": "Borrar", + "四角": "Rect", + "線四角": "LíneaRect", + "楕円": "Óvalo", + "線楕円": "LíneaÓvalo", + "コピー": "Copiar", + "レイヤ結合": "UnirCapa", + "角取り": "Antialias", + "左右反転": "Inv.Izq/Der", + "上下反転": "Inv.Arr/Aba", + "傾け": "Inclinar", + "通常": "Normal", + "マスク": "Masc.", + "逆マスク": "Masc.Inv", + "加算": "Adición", + "逆加算": "Subtrac", + "手書き": "Libre", + "直線": "Línea", + "BZ曲線": "Curva", + "Layer0": "Capa0", + "Layer1": "Capa1", + "ページビュー?": "¿Vista de página?", + "ウィンドウビュー?": "¿Vista de ventana?", + "以前の編集データを復元しますか?": "¿Restaurar sesión anterior?", + "右": "Clic derecho", + + "PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?": + "PaintBBS NEO es una versión para HTML5 de Oekaki Shi-BBS PaintBBS (© 2000-2004 shi-chan). ¿Mostrar la página del proyecto?", + "このブラウザでは<br>投稿に失敗することがあります<br>": "Este navegador podría no enviar su imagen.<br>", + }, +}; + +Neo.translate = function () { + var language = (window.navigator.languages && window.navigator.languages[0]) || + window.navigator.language || + window.navigator.userLanguage || + window.navigator.browserLanguage; + + var lang = "en"; + for (var key in Neo.dictionary) { + if (language.indexOf(key) == 0) { + lang = key; + break; + } + } + + return function(string) { + if (Neo.config.neo_alt_translation) { + if (lang == "en") lang = "enx" + } else { + if (lang != "ja") lang = "en" + } + return Neo.dictionary[lang][string] || string; + } +}(); + + +'use strict'; + +Neo.Painter = function() { + this._undoMgr = new Neo.UndoManager(50); +}; + +Neo.Painter.prototype.container; +Neo.Painter.prototype._undoMgr; +Neo.Painter.prototype.tool; +Neo.Painter.prototype.inputText; + +//Canvas Info +Neo.Painter.prototype.canvasWidth; +Neo.Painter.prototype.canvasHeight; +Neo.Painter.prototype.canvas = []; +Neo.Painter.prototype.canvasCtx = []; +Neo.Painter.prototype.visible = []; +Neo.Painter.prototype.current = 0; + +//Temp Canvas Info +Neo.Painter.prototype.tempCanvas; +Neo.Painter.prototype.tempCanvasCtx; +Neo.Painter.prototype.tempX = 0; +Neo.Painter.prototype.tempY = 0; + +//Destination Canvas for display +Neo.Painter.prototype.destCanvas; +Neo.Painter.prototype.destCanvasCtx; + + +Neo.Painter.prototype.backgroundColor = "#ffffff"; +Neo.Painter.prototype.foregroundColor = "#000000"; + +Neo.Painter.prototype.lineWidth = 1; +Neo.Painter.prototype.alpha = 1; +Neo.Painter.prototype.zoom = 1; +Neo.Painter.prototype.zoomX = 0; +Neo.Painter.prototype.zoomY = 0; + +Neo.Painter.prototype.isMouseDown; +Neo.Painter.prototype.isMouseDownRight; +Neo.Painter.prototype.prevMouseX; +Neo.Painter.prototype.prevMouseY; +Neo.Painter.prototype.mouseX; +Neo.Painter.prototype.mouseY; + +Neo.Painter.prototype.slowX = 0; +Neo.Painter.prototype.slowY = 0; +Neo.Painter.prototype.stab = null; + +Neo.Painter.prototype.isShiftDown = false; +Neo.Painter.prototype.isCtrlDown = false; +Neo.Painter.prototype.isAltDown = false; + +//Neo.Painter.prototype.touchModifier = null; +Neo.Painter.prototype.virtualRight = false; +Neo.Painter.prototype.virtualShift = false; + +//Neo.Painter.prototype.onUpdateCanvas; +Neo.Painter.prototype._roundData = []; +Neo.Painter.prototype._toneData = []; +Neo.Painter.prototype.toolStack = []; + +Neo.Painter.prototype.maskType = 0; +Neo.Painter.prototype.drawType = 0; +Neo.Painter.prototype.maskColor = "#000000"; +Neo.Painter.prototype._currentColor = []; +Neo.Painter.prototype._currentMask = []; + +Neo.Painter.prototype.aerr; + +Neo.Painter.LINETYPE_NONE = 0; +Neo.Painter.LINETYPE_PEN = 1; +Neo.Painter.LINETYPE_ERASER = 2; +Neo.Painter.LINETYPE_BRUSH = 3; +Neo.Painter.LINETYPE_TONE = 4; +Neo.Painter.LINETYPE_DODGE = 5; +Neo.Painter.LINETYPE_BURN = 6; + +Neo.Painter.MASKTYPE_NONE = 0; +Neo.Painter.MASKTYPE_NORMAL = 1; +Neo.Painter.MASKTYPE_REVERSE = 2; +Neo.Painter.MASKTYPE_ADD = 3; +Neo.Painter.MASKTYPE_SUB = 4; + +Neo.Painter.DRAWTYPE_FREEHAND = 0; +Neo.Painter.DRAWTYPE_LINE = 1; +Neo.Painter.DRAWTYPE_BEZIER = 2; + +Neo.Painter.ALPHATYPE_NONE = 0; +Neo.Painter.ALPHATYPE_PEN = 1; +Neo.Painter.ALPHATYPE_FILL = 2; +Neo.Painter.ALPHATYPE_BRUSH = 3; + +Neo.Painter.TOOLTYPE_NONE = 0; +Neo.Painter.TOOLTYPE_PEN = 1; +Neo.Painter.TOOLTYPE_ERASER = 2; +Neo.Painter.TOOLTYPE_HAND = 3; +Neo.Painter.TOOLTYPE_SLIDER = 4; +Neo.Painter.TOOLTYPE_FILL = 5; +Neo.Painter.TOOLTYPE_MASK = 6; +Neo.Painter.TOOLTYPE_ERASEALL = 7; +Neo.Painter.TOOLTYPE_ERASERECT = 8; +Neo.Painter.TOOLTYPE_COPY = 9; +Neo.Painter.TOOLTYPE_PASTE = 10; +Neo.Painter.TOOLTYPE_MERGE = 11; +Neo.Painter.TOOLTYPE_FLIP_H = 12; +Neo.Painter.TOOLTYPE_FLIP_V = 13; + +Neo.Painter.TOOLTYPE_BRUSH = 14; +Neo.Painter.TOOLTYPE_TEXT = 15; +Neo.Painter.TOOLTYPE_TONE = 16; +Neo.Painter.TOOLTYPE_BLUR = 17; +Neo.Painter.TOOLTYPE_DODGE = 18; +Neo.Painter.TOOLTYPE_BURN = 19; +Neo.Painter.TOOLTYPE_RECT = 20; +Neo.Painter.TOOLTYPE_RECTFILL = 21; +Neo.Painter.TOOLTYPE_ELLIPSE = 22; +Neo.Painter.TOOLTYPE_ELLIPSEFILL = 23; +Neo.Painter.TOOLTYPE_BLURRECT = 24; +Neo.Painter.TOOLTYPE_TURN = 25; + +Neo.Painter.prototype.build = function(div, width, height) +{ + this.container = div; + this._initCanvas(div, width, height); + this._initRoundData(); + this._initToneData(); + this._initInputText(); + + this.setTool(new Neo.PenTool()); + +}; + +Neo.Painter.prototype.setTool = function(tool) { + if (this.tool && this.tool.saveStates) this.tool.saveStates(); + + if (this.tool && this.tool.kill) { + this.tool.kill(); + } + this.tool = tool; + tool.init(); + if (this.tool && this.tool.loadStates) this.tool.loadStates(); +}; + +Neo.Painter.prototype.pushTool = function(tool) { + this.toolStack.push(this.tool); + this.tool = tool; + tool.init(); +}; + +Neo.Painter.prototype.popTool = function() { + var tool = this.tool; + if (tool && tool.kill) { + tool.kill(); + } + this.tool = this.toolStack.pop(); +}; + +Neo.Painter.prototype.getCurrentTool = function() { + if (this.tool) { + var tool = this.tool; + if (tool && tool.type == Neo.Painter.TOOLTYPE_SLIDER) { + var stack = this.toolStack; + if (stack.length > 0) { + tool = stack[stack.length - 1]; + } + } + return tool; + } + return null; +}; + +Neo.Painter.prototype.setToolByType = function(toolType) { + switch (parseInt(toolType)) { + case Neo.Painter.TOOLTYPE_PEN: this.setTool(new Neo.PenTool()); break; + case Neo.Painter.TOOLTYPE_ERASER: this.setTool(new Neo.EraserTool()); break; + case Neo.Painter.TOOLTYPE_HAND: this.setTool(new Neo.HandTool()); break; + case Neo.Painter.TOOLTYPE_FILL: this.setTool(new Neo.FillTool()); break; + case Neo.Painter.TOOLTYPE_ERASEALL: this.setTool(new Neo.EraseAllTool()); break; + case Neo.Painter.TOOLTYPE_ERASERECT: this.setTool(new Neo.EraseRectTool()); break; + + case Neo.Painter.TOOLTYPE_COPY: this.setTool(new Neo.CopyTool()); break; + case Neo.Painter.TOOLTYPE_PASTE: this.setTool(new Neo.PasteTool()); break; + case Neo.Painter.TOOLTYPE_MERGE: this.setTool(new Neo.MergeTool()); break; + case Neo.Painter.TOOLTYPE_FLIP_H: this.setTool(new Neo.FlipHTool()); break; + case Neo.Painter.TOOLTYPE_FLIP_V: this.setTool(new Neo.FlipVTool()); break; + + case Neo.Painter.TOOLTYPE_BRUSH: this.setTool(new Neo.BrushTool()); break; + case Neo.Painter.TOOLTYPE_TEXT: this.setTool(new Neo.TextTool()); break; + case Neo.Painter.TOOLTYPE_TONE: this.setTool(new Neo.ToneTool()); break; + case Neo.Painter.TOOLTYPE_BLUR: this.setTool(new Neo.BlurTool()); break; + case Neo.Painter.TOOLTYPE_DODGE: this.setTool(new Neo.DodgeTool()); break; + case Neo.Painter.TOOLTYPE_BURN: this.setTool(new Neo.BurnTool()); break; + + case Neo.Painter.TOOLTYPE_RECT: this.setTool(new Neo.RectTool()); break; + case Neo.Painter.TOOLTYPE_RECTFILL: this.setTool(new Neo.RectFillTool()); break; + case Neo.Painter.TOOLTYPE_ELLIPSE: this.setTool(new Neo.EllipseTool()); break; + case Neo.Painter.TOOLTYPE_ELLIPSEFILL:this.setTool(new Neo.EllipseFillTool()); break; + case Neo.Painter.TOOLTYPE_BLURRECT: this.setTool(new Neo.BlurRectTool()); break; + case Neo.Painter.TOOLTYPE_TURN: this.setTool(new Neo.TurnTool()); break; + + default: + console.log("unknown toolType " + toolType); + break; + } +}; + +Neo.Painter.prototype._initCanvas = function(div, width, height) { + width = parseInt(width); + height = parseInt(height); + var destWidth = parseInt(div.clientWidth); + var destHeight = parseInt(div.clientHeight); + this.destWidth = width; + this.destHeight = height; + + this.canvasWidth = width; + this.canvasHeight = height; + this.zoomX = width * 0.5; + this.zoomY = height * 0.5; + + for (var i = 0; i < 2; i++) { + this.canvas[i] = document.createElement("canvas"); + this.canvas[i].width = width; + this.canvas[i].height = height; + this.canvasCtx[i] = this.canvas[i].getContext("2d"); + + this.canvas[i].style.imageRendering = "pixelated"; + this.canvasCtx[i].imageSmoothingEnabled = false; + this.canvasCtx[i].mozImageSmoothingEnabled = false; + this.visible[i] = true; + } + + this.tempCanvas = document.createElement("canvas"); + this.tempCanvas.width = width; + this.tempCanvas.height = height; + this.tempCanvasCtx = this.tempCanvas.getContext("2d"); + this.tempCanvas.style.position = "absolute"; + this.tempCanvas.enabled = false; + + var array = this.container.getElementsByTagName("canvas"); + if (array.length > 0) { + this.destCanvas = array[0]; + } else { + this.destCanvas = document.createElement("canvas"); + this.container.appendChild(this.destCanvas); + } + + this.destCanvasCtx = this.destCanvas.getContext("2d"); + this.destCanvas.width = destWidth; + this.destCanvas.height = destHeight; + + this.destCanvas.style.imageRendering = "pixelated"; + this.destCanvasCtx.imageSmoothingEnabled = false; + this.destCanvasCtx.mozImageSmoothingEnabled = false; + + var ref = this; + + var container = document.getElementById("container"); + + container.onmousedown = function(e) {ref._mouseDownHandler(e)}; + container.onmousemove = function(e) {ref._mouseMoveHandler(e)}; + container.onmouseup = function(e) {ref._mouseUpHandler(e)}; + container.onmouseover = function(e) {ref._rollOverHandler(e)}; + container.onmouseout = function(e) {ref._rollOutHandler(e)}; + container.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + }, false); + container.addEventListener("touchmove", function(e) { + ref._mouseMoveHandler(e); + }, false); + container.addEventListener("touchend", function(e) { + ref._mouseUpHandler(e); + }, false); + + document.onkeydown = function(e) {ref._keyDownHandler(e)}; + document.onkeyup = function(e) {ref._keyUpHandler(e)}; + + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype._initRoundData = function() { + for (var r = 1; r <= 30; r++) { + this._roundData[r] = new Uint8Array(r * r); + var mask = this._roundData[r]; + var d = Math.floor(r / 2.0); + var index = 0; + for (var x = 0; x < r; x++) { + for (var y = 0; y < r; y++) { + var xx = x + 0.5 - r/2.0; + var yy = y + 0.5 - r/2.0; + mask[index++] = (xx*xx + yy*yy <= r*r/4) ? 1 : 0; + } + } + } + this._roundData[3][0] = 0; + this._roundData[3][2] = 0; + this._roundData[3][6] = 0; + this._roundData[3][8] = 0; + + this._roundData[5][1] = 0; + this._roundData[5][3] = 0; + this._roundData[5][5] = 0; + this._roundData[5][9] = 0; + this._roundData[5][15] = 0; + this._roundData[5][19] = 0; + this._roundData[5][21] = 0; + this._roundData[5][23] = 0; +}; + +Neo.Painter.prototype._initToneData = function() { + var pattern = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5]; + + for (var i = 0; i < 16; i++) { + this._toneData[i] = new Uint8Array(16); + for (var j = 0; j < 16; j++) { + this._toneData[i][j] = (i >= pattern[j]) ? 1 : 0; + } + } +}; + +Neo.Painter.prototype.getToneData = function(alpha) { + var alphaTable = [23, + 47, + 69, + 92, + 114, + 114, + 114, + 138, + 161, + 184, + 184, + 207, + 230, + 230, + 253, + ]; + + for (var i = 0; i < alphaTable.length; i++) { + if (alpha < alphaTable[i]) { + return this._toneData[i]; + } + } + return this._toneData[i]; +}; + +Neo.Painter.prototype._initInputText = function() { + var text = document.getElementById("inputtext"); + if (!text) { + text = document.createElement("div"); + } + + text.id = "inputext"; + text.setAttribute("contentEditable", true); + text.spellcheck = false; + text.className = "inputText"; + text.innerHTML = ""; + + text.style.display = "none"; +// text.style.userSelect = "none"; + Neo.painter.container.appendChild(text); + this.inputText = text; + + this.updateInputText(); +}; + +Neo.Painter.prototype.hideInputText = function() { + var text = this.inputText; + text.blur(); + text.style.display = "none"; +}; + +Neo.Painter.prototype.updateInputText = function() { + var text = this.inputText; + var d = this.lineWidth; + var fontSize = Math.round(d * 55/28 + 7); + var height = Math.round(d * 68/28 + 12); + + text.style.fontSize = fontSize + "px"; + text.style.lineHeight = fontSize + "px"; + text.style.height = fontSize + "px"; + text.style.marginTop = -fontSize + "px"; +}; + +/* +----------------------------------------------------------------------- + Mouse Event Handling +----------------------------------------------------------------------- +*/ + +Neo.Painter.prototype._keyDownHandler = function(e) { + this.isShiftDown = e.shiftKey; + this.isCtrlDown = e.ctrlKey; + this.isAltDown = e.altKey; + if (e.keyCode == 32) this.isSpaceDown = true; + + if (!this.isShiftDown && this.isCtrlDown) { + if (!this.isAltDown) { + if (e.keyCode == 90 || e.keyCode == 85) this.undo(); //Ctrl+Z,Ctrl.U + if (e.keyCode == 89) this.redo(); //Ctrl+Y + } else { + if (e.keyCode == 90) this.redo(); //Ctrl+Alt+Z + } + } + + if (!this.isShiftDown && !this.isCtrlDown && !this.isAltDown) { + if (e.keyCode == 107) new Neo.ZoomPlusCommand(this).execute(); // + + if (e.keyCode == 109) new Neo.ZoomMinusCommand(this).execute(); // - + } + + if (this.tool.keyDownHandler) { + this.tool.keyDownHandler(e); + } + + //スペース・Shift+スペースででスクロールしないように + if (document.activeElement != this.inputText) e.preventDefault(); +}; + +Neo.Painter.prototype._keyUpHandler = function(e) { + this.isShiftDown = e.shiftKey; + this.isCtrlDown = e.ctrlKey; + this.isAltDown = e.altKey; + if (e.keyCode == 32) this.isSpaceDown = false; + + if (this.tool.keyUpHandler) { + this.tool.keyUpHandler(oe); + } +}; + +Neo.Painter.prototype._rollOverHandler = function(e) { + if (this.tool.rollOverHandler) { + this.tool.rollOverHandler(this); + } +}; + +Neo.Painter.prototype._rollOutHandler = function(e) { + if (this.tool.rollOutHandler) { + this.tool.rollOutHandler(this); + } +}; + +Neo.Painter.prototype._mouseDownHandler = function(e) { + if (e.target == Neo.painter.destCanvas) { + //よくわからないがChromeでドラッグの時カレットが出るのを防ぐ + //http://stackoverflow.com/questions/2745028/chrome-sets-cursor-to-text-while-dragging-why + e.preventDefault(); + } + + if (e.type == "touchstart" && e.touches.length > 1) return; + + if (e.button == 2 || this.virtualRight) { + this.isMouseDownRight = true; + + } else { + if (!e.shiftKey && e.ctrlKey && e.altKey) { + this.isMouseDown = true; + + } else { + if (e.ctrlKey || e.altKey) { + this.isMouseDownRight = true; + } else { + this.isMouseDown = true; + } + } + } + + this._updateMousePosition(e); + this.prevMouseX = this.mouseX; + this.prevMouseY = this.mouseY; + + if (this.isMouseDownRight) { + this.isMouseDownRight = false; + if (!this.isWidget(e.target)) { + this.pickColor(this.mouseX, this.mouseY); + return; + } + } + + if (!this.isUIPaused()) { + if (e.target['data-bar']) { + this.pushTool(new Neo.HandTool()); + + } else if (this.isSpaceDown && document.activeElement != this.inputText) { + this.pushTool(new Neo.HandTool()); + this.tool.reverse = true; + + } else if (e.target['data-slider'] != undefined) { + this.pushTool(new Neo.SliderTool()); + this.tool.target = e.target; + + } else if (e.ctrlKey && e.altKey && !e.shiftKey) { + this.pushTool(new Neo.SliderTool()); + this.tool.target = Neo.sliders[Neo.SLIDERTYPE_SIZE].element; + this.tool.alt = true; + + } else if (this.isWidget(e.target)) { + this.isMouseDown = false; + this.pushTool(new Neo.DummyTool()); + + } + } + +// console.warn("down -" + e.target.id + e.target.className) + if (!(e.target.className == "o" && e.type == "touchdown")) { + this.tool.downHandler(this); + } + +// var ref = this; +// document.onmouseup = function(e) { +// ref._mouseUpHandler(e) +// }; +}; + +Neo.Painter.prototype._mouseUpHandler = function(e) { + this.isMouseDown = false; + this.isMouseDownRight = false; + this.tool.upHandler(this); +// document.onmouseup = undefined; + + if (e.target.id != "right") { + this.virtualRight = false; + Neo.RightButton.clear(); + } + +// if (e.changedTouches) { +// for (var i = 0; i < e.changedTouches.length; i++) { +// var touch = e.changedTouches[i]; +// if (touch.identifier == this.touchModifier) { +// this.touchModifier = null; +// } +// } +// } +}; + +Neo.Painter.prototype._mouseMoveHandler = function(e) { + this._updateMousePosition(e); + + if (e.type == "touchmove" && e.touches.length > 1) return; + + if (this.isMouseDown || this.isMouseDownRight) { + this.tool.moveHandler(this); + + } else { + if (this.tool.upMoveHandler) { + this.tool.upMoveHandler(this); + } + } + + this.prevMouseX = this.mouseX; + this.prevMouseY = this.mouseY; + + // 画面外をタップした時スクロール可能にするため +// console.warn("move -" + e.target.id + e.target.className) + if (!(e.target.className == "o" && e.type == "touchmove")) { + e.preventDefault(); + } +}; + + +Neo.Painter.prototype.getPosition = function(e) { + if (e.clientX !== undefined) { + return {x: e.clientX, y: e.clientY, e: e.type}; + + } else { + var touch = e.changedTouches[0]; + return {x: touch.clientX, y: touch.clientY, e: e.type}; + +// for (var i = 0; i < e.changedTouches.length; i++) { +// var touch = e.changedTouches[i]; +// if (!this.touchModifier || this.touchModifier != touch.identifier) { +// return {x: touch.clientX, y: touch.clientY, e: e.type}; +// } +// } +// console.log("getPosition error"); +// return {x:0, y:0}; + } +} + +Neo.Painter.prototype._updateMousePosition = function(e) { + var rect = this.destCanvas.getBoundingClientRect(); +// var x = (e.clientX !== undefined) ? e.clientX : e.touches[0].clientX; +// var y = (e.clientY !== undefined) ? e.clientY : e.touches[0].clientY; + var pos = this.getPosition(e); + var x = pos.x; + var y = pos.y; + + if (this.zoom <= 0) this.zoom = 1; //なぜか0になることがあるので + + this.mouseX = (x - rect.left) / this.zoom + + this.zoomX + - this.destCanvas.width * 0.5 / this.zoom; + this.mouseY = (y - rect.top) / this.zoom + + this.zoomY + - this.destCanvas.height * 0.5 / this.zoom; + + if (isNaN(this.prevMouseX)) { + this.prevMouseX = this.mouseX; + } + if (isNaN(this.prevMouseY)) { + this.prevMosueY = this.mouseY; + } + + this.slowX = this.slowX * 0.8 + this.mouseX * 0.2; + this.slowY = this.slowY * 0.8 + this.mouseY * 0.2; + var now = new Date().getTime(); + if (this.stab) { + var pause = this.stab[3]; + if (pause) { + // ポーズ中 + if (now > pause) { + this.stab = [this.slowX, this.slowY, now]; + } + + } else { + // ポーズされていないとき + var prev = this.stab[2]; + if (now - prev > 150) { // 150ms以上止まっていたらポーズをオンにする + this.stab[3] = now + 200 // 200msペンの位置を固定 + + } else { + this.stab = [this.slowX, this.slowY, now]; + } + } + } else { + this.stab = [this.slowX, this.slowY, now]; + } + + this.rawMouseX = x; + this.rawMouseY = y; + this.clipMouseX = Math.max(Math.min(this.canvasWidth, this.mouseX), 0); + this.clipMouseY = Math.max(Math.min(this.canvasHeight, this.mouseY), 0); +}; + +Neo.Painter.prototype._beforeUnloadHandler = function(e) { + // quick save +}; + +Neo.Painter.prototype.getStabilized = function() { + return this.stab; +}; + +/* +------------------------------------------------------------------------- + Undo +------------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.undo = function() { + var undoItem = this._undoMgr.popUndo(); + if (undoItem) { + this._pushRedo(); + this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y); + this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y); + this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height); + } +}; + +Neo.Painter.prototype.redo = function() { + var undoItem = this._undoMgr.popRedo(); + if (undoItem) { + this._pushUndo(0,0,this.canvasWidth, this.canvasHeight, true); + this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y); + this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y); + this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height); + } +}; + +Neo.Painter.prototype.hasUndo = function() { + return true; +}; + +Neo.Painter.prototype._pushUndo = function(x, y, w, h, holdRedo) { + x = (x === undefined) ? 0 : x; + y = (y === undefined) ? 0 : y; + w = (w === undefined) ? this.canvasWidth : w; + h = (h === undefined) ? this.canvasHeight : h; + var undoItem = new Neo.UndoItem(); + undoItem.x = 0; + undoItem.y = 0; + undoItem.width = w; + undoItem.height = h; + undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h), + this.canvasCtx[1].getImageData(x, y, w, h)]; + this._undoMgr.pushUndo(undoItem, holdRedo); +}; + +Neo.Painter.prototype._pushRedo = function(x, y, w, h) { + x = (x === undefined) ? 0 : x; + y = (y === undefined) ? 0 : y; + w = (w === undefined) ? this.canvasWidth : w; + h = (h === undefined) ? this.canvasHeight : h; + var undoItem = new Neo.UndoItem(); + undoItem.x = 0; + undoItem.y = 0; + undoItem.width = w; + undoItem.height = h; + undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h), + this.canvasCtx[1].getImageData(x, y, w, h)]; + this._undoMgr.pushRedo(undoItem); +}; + + +/* +------------------------------------------------------------------------- + Data Cache for Undo / Redo +------------------------------------------------------------------------- +*/ + +Neo.UndoManager = function(_maxStep){ + this._maxStep = _maxStep; + this._undoItems = []; + this._redoItems = []; +} +Neo.UndoManager.prototype._maxStep; +Neo.UndoManager.prototype._redoItems; +Neo.UndoManager.prototype._undoItems; + +//アクションをしてUndo情報を更新 +Neo.UndoManager.prototype.pushUndo = function(undoItem, holdRedo) { + this._undoItems.push(undoItem); + if (this._undoItems.length > this._maxStep) { + this._undoItems.shift(); + } + + if (!holdRedo == true) { + this._redoItems = []; + } +}; + +Neo.UndoManager.prototype.popUndo = function() { + return this._undoItems.pop(); +} + +Neo.UndoManager.prototype.pushRedo = function(undoItem) { + this._redoItems.push(undoItem); +} + +Neo.UndoManager.prototype.popRedo = function() { + return this._redoItems.pop(); +} + + +Neo.UndoItem = function() {} +Neo.UndoItem.prototype.data; +Neo.UndoItem.prototype.x; +Neo.UndoItem.prototype.y; +Neo.UndoItem.prototype.width; +Neo.UndoItem.prototype.height; + +/* +------------------------------------------------------------------------- + Zoom Controller +------------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.setZoom = function(value) { + this.zoom = value; + + var container = document.getElementById("container"); + var width = this.canvasWidth * this.zoom; + var height = this.canvasHeight * this.zoom; + if (width > container.clientWidth - 100) width = container.clientWidth - 100; + if (height > container.clientHeight - 130) height = container.clientHeight - 130; + this.destWidth = width; + this.destHeight = height; + + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight, false); + this.setZoomPosition(this.zoomX, this.zoomY); +}; + +Neo.Painter.prototype.setZoomPosition = function(x, y) { + var minx = (this.destCanvas.width / this.zoom) * 0.5; + var maxx = this.canvasWidth - minx; + var miny = (this.destCanvas.height / this.zoom) * 0.5; + var maxy = this.canvasHeight - miny; + + + x = Math.round(Math.max(Math.min(maxx,x),minx)); + y = Math.round(Math.max(Math.min(maxy,y),miny)); + + this.zoomX = x; + this.zoomY = y; + this.updateDestCanvas(0,0,this.canvasWidth,this.canvasHeight,false); + + this.scrollBarX = (maxx == minx) ? 0 : (x - minx) / (maxx - minx); + this.scrollBarY = (maxy == miny) ? 0 : (y - miny) / (maxy - miny); + this.scrollWidth = maxx - minx; + this.scrollHeight = maxy - miny; + + if (Neo.scrollH) Neo.scrollH.update(this); + if (Neo.scrollV) Neo.scrollV.update(this); + + this.hideInputText(); +}; + + +/* +------------------------------------------------------------------------- + Drawing Helper +------------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.submit = function(board) { + var thumbnail = null; + var thumbnail2 = null; + + if (this.useThumbnail()) { + thumbnail = this.getThumbnail(Neo.config.thumbnail_type || "png"); + if (Neo.config.thumbnail_type2) { + thumbnail2 = this.getThumbnail(Neo.config.thumbnail_type2); + } + } + Neo.submit(board, this.getPNG(), thumbnail2, thumbnail); +}; + +Neo.Painter.prototype.useThumbnail = function() { + var thumbnailWidth = this.getThumbnailWidth(); + var thumbnailHeight = this.getThumbnailHeight(); + if (thumbnailWidth && thumbnailHeight) { + if (thumbnailWidth < this.canvasWidth || + thumbnailHeight < this.canvasHeight) { + return true; + } + } + return false; +}; + +Neo.Painter.prototype.dataURLtoBlob = function(dataURL) { + var byteString; + if (dataURL.split(',')[0].indexOf('base64') >= 0) { + byteString = atob(dataURL.split(',')[1]); + } else { + byteString = unescape(dataURL.split(',')[1]); + } + + // write the bytes of the string to a typed array + var ia = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + return new Blob([ia], {type:'image/png'}); +}; + +Neo.Painter.prototype.getImage = function(imageWidth, imageHeight) { + var width = this.canvasWidth; + var height = this.canvasHeight; + imageWidth = imageWidth || width; + imageHeight = imageHeight || height; + + var pngCanvas = document.createElement("canvas"); + pngCanvas.width = imageWidth; + pngCanvas.height = imageHeight; + var pngCanvasCtx = pngCanvas.getContext("2d"); + pngCanvasCtx.fillStyle = "#ffffff"; + pngCanvasCtx.fillRect(0, 0, imageWidth, imageHeight); + + if (this.visible[0]) { + pngCanvasCtx.drawImage(this.canvas[0], + 0, 0, width, height, + 0, 0, imageWidth, imageHeight); + } + if (this.visible[1]) { + pngCanvasCtx.drawImage(this.canvas[1], + 0, 0, width, height, + 0, 0, imageWidth, imageHeight); + } + return pngCanvas; +}; + +Neo.Painter.prototype.getPNG = function() { + var image = this.getImage(); + var dataURL = image.toDataURL('image/png'); + return this.dataURLtoBlob(dataURL); +}; + +Neo.Painter.prototype.getThumbnail = function(type) { + if (type != "animation") { + var thumbnailWidth = this.getThumbnailWidth(); + var thumbnailHeight = this.getThumbnailHeight(); + if (thumbnailWidth || thumbnailHeight) { + var width = this.canvasWidth; + var height = this.canvasHeight; + if (thumbnailWidth == 0) { + thumbnailWidth = thumbnailHeight * width / height; + } + if (thumbnailHeight == 0) { + thumbnailHeight = thumbnailWidth * height / width; + } + } else { + thumbnailWidth = thumbnailHeight = null; + } + + console.log("get thumbnail", thumbnailWidth, thumbnailHeight); + + var image = this.getImage(thumbnailWidth, thumbnailHeight); + var dataURL = image.toDataURL('image/' + type); + return this.dataURLtoBlob(dataURL); + + } else { + return new Blob([]); //animationには対応していないのでダミーデータを返す + } +}; + +Neo.Painter.prototype.getThumbnailWidth = function() { + var width = Neo.config.thumbnail_width; + if (width) { + if (width.match(/%$/)) { + return Math.floor(this.canvasWidth * (parseInt(width) / 100.0)); + } else { + return parseInt(width); + } + } + return 0; +}; + +Neo.Painter.prototype.getThumbnailHeight = function() { + var height = Neo.config.thumbnail_height; + if (height) { + if (height.match(/%$/)) { + return Math.floor(this.canvasHeight * (parseInt(height) / 100.0)); + } else { + return parseInt(height); + } + } + return 0; +}; + +Neo.Painter.prototype.clearCanvas = function(doConfirm) { + if (!doConfirm || confirm("全消しします")) { + //Register undo first; + this._pushUndo(); + + this.canvasCtx[0].clearRect(0, 0, this.canvasWidth, this.canvasHeight); + this.canvasCtx[1].clearRect(0, 0, this.canvasWidth, this.canvasHeight); + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight); + } +}; + +Neo.Painter.prototype.updateDestCanvas = function(x, y, width, height, useTemp) { + var canvasWidth = this.canvasWidth; + var canvasHeight = this.canvasHeight; + var updateAll = false; + if (x == 0 && y == 0 && width == canvasWidth && height == canvasHeight) { + updateAll = true; + }; + + if (x + width > this.canvasWidth) width = this.canvasWidth - x; + if (y + height > this.canvasHeight) height = this.canvasHeight - y; + if (x < 0) x = 0; + if (y < 0) y = 0; + if (width <= 0 || height <= 0) return; + + var ctx = this.destCanvasCtx; + ctx.save(); + ctx.fillStyle = "#ffffff"; + + var fillWidth = width + var fillHeight = height + + if (updateAll) { + ctx.fillRect(0, 0, this.destCanvas.width, this.destCanvas.height); + + } else { + //カーソルの描画ゴミが残るのをごまかすため + if (x + width == this.canvasWidth) fillWidth = width + 1; + if (y + height == this.canvasHeight) fillHeight = height + 1; + } + + ctx.translate(this.destCanvas.width*.5, this.destCanvas.height*.5); + ctx.scale(this.zoom, this.zoom); + ctx.translate(-this.zoomX, -this.zoomY); + ctx.globalAlpha = 1.0; + ctx.msImageSmoothingEnabled = 0; + + if (!updateAll) { + ctx.fillRect(x, y, fillWidth, fillHeight); + } + + if (this.visible[0]) { + ctx.drawImage(this.canvas[0], + x, y, width, height, + x, y, width, height); + } + if (this.visible[1]) { + ctx.drawImage(this.canvas[1], + x, y, width, height, + x, y, width, height); + } + if (useTemp) { + ctx.globalAlpha = 1.0; //this.alpha; + ctx.drawImage(this.tempCanvas, + x, y, width, height, + x + this.tempX, y + this.tempY, width, height); + } + ctx.restore(); +}; + +Neo.Painter.prototype.getBound = function(x0, y0, x1, y1, r) { + var left = Math.floor((x0 < x1) ? x0 : x1); + var top = Math.floor((y0 < y1) ? y0 : y1); + var width = Math.ceil(Math.abs(x0 - x1)); + var height = Math.ceil(Math.abs(y0 - y1)); + r = Math.ceil(r + 1); + + if (!r) { + width += 1; + height += 1; + + } else { + left -= r; + top -= r; + width += r * 2; + height += r * 2; + } + return [left, top, width, height]; +}; + +Neo.Painter.prototype.getColor = function(c) { + if (!c) c = this.foregroundColor; + var r = parseInt(c.substr(1, 2), 16); + var g = parseInt(c.substr(3, 2), 16); + var b = parseInt(c.substr(5, 2), 16); + var a = Math.floor(this.alpha * 255); + return a <<24 | b<<16 | g<<8 | r; +}; + +Neo.Painter.prototype.getColorString = function(c) { + var rgb = ("000000" + (c & 0xffffff).toString(16)).substr(-6); + return '#' + rgb; +}; + +Neo.Painter.prototype.setColor = function(c) { + if (typeof c != "string") c = this.getColorString(c); + this.foregroundColor = c; + + Neo.updateUI(); +}; + +Neo.Painter.prototype.getAlpha = function(type) { + var a1 = this.alpha; + + switch (type) { + case Neo.Painter.ALPHATYPE_PEN: + if (a1 > 0.5) { + a1 = 1.0/16 + (a1 - 0.5) * 30.0/16; + } else { + a1 = Math.sqrt(2 * a1) / 16.0; + } + a1 = Math.min(1, Math.max(0, a1)); + break; + + case Neo.Painter.ALPHATYPE_FILL: + a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042; + a1 = Math.min(1.0, Math.max(0, a1 * 10)); + break; + + case Neo.Painter.ALPHATYPE_BRUSH: + a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042; + a1 = Math.min(1.0, Math.max(0, a1)); + break; + } + + // アルファが小さい時は適当に点を抜いて見た目の濃度を合わせる + if (a1 < 1.0/255) { + this.aerr += a1; + a1 = 0; + while (this.aerr > 1.0/255) { + a1 = 1.0/255; + this.aerr -= 1.0/255; + } + } + return a1; +}; + +Neo.Painter.prototype.prepareDrawing = function () { + var r = parseInt(this.foregroundColor.substr(1, 2), 16); + var g = parseInt(this.foregroundColor.substr(3, 2), 16); + var b = parseInt(this.foregroundColor.substr(5, 2), 16); + var a = Math.floor(this.alpha * 255); + + var maskR = parseInt(this.maskColor.substr(1, 2), 16); + var maskG = parseInt(this.maskColor.substr(3, 2), 16); + var maskB = parseInt(this.maskColor.substr(5, 2), 16); + + this._currentColor = [r, g, b, a]; + this._currentMask = [maskR, maskG, maskB]; +}; + +Neo.Painter.prototype.isMasked = function (buf8, index) { + var r = this._currentMask[0]; + var g = this._currentMask[1]; + var b = this._currentMask[2]; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3]; + + if (a0 == 0) { + r0 = 0xff; + g0 = 0xff; + b0 = 0xff; + } + + var type = this.maskType; + + //TODO + //いろいろ試したのですが半透明で描画するときの加算・逆加算を再現する方法がわかりません。 + //とりあえず単純に無視しています。 + if (type == Neo.Painter.MASKTYPE_ADD || + type == Neo.Painter.MASKTYPE_SUB) { + if (this._currentColor[3] < 250) { + type = Neo.Painter.MASKTYPE_NONE; + } + } + + switch (type) { + case Neo.Painter.MASKTYPE_NONE: + return; + + case Neo.Painter.MASKTYPE_NORMAL: + return (r0 == r && + g0 == g && + b0 == b) ? true : false; + + case Neo.Painter.MASKTYPE_REVERSE: + return (r0 != r || + g0 != g || + b0 != b) ? true : false; + + case Neo.Painter.MASKTYPE_ADD: + if (a0 > 0) { + var sort = this.sortColor(r0, g0, b0); + for (var i = 0; i < 3; i++) { + var c = sort[i]; + if (buf8[index + c] < this._currentColor[c]) return true; + } + return false; + + } else { + return false; + } + + case Neo.Painter.MASKTYPE_SUB: + if (a0 > 0) { + var sort = this.sortColor(r0, g0, b0); + for (var i = 0; i < 3; i++) { + var c = sort[i]; + if (buf8[index + c] > this._currentColor[c]) return true; + } + return false; + } else { + return true; + } + } +}; + +Neo.Painter.prototype.setPoint = function(buf8, bufWidth, x0, y0, left, top, type) { + var x = x0 - left; + var y = y0 - top; + + switch (type) { + case Neo.Painter.LINETYPE_PEN: + this.setPenPoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_BRUSH: + this.setBrushPoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_TONE: + this.setTonePoint(buf8, bufWidth, x, y, x0, y0); + break; + + case Neo.Painter.LINETYPE_ERASER: + this.setEraserPoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_BLUR: + this.setBlurPoint(buf8, bufWidth, x, y, x0, y0); + break; + + case Neo.Painter.LINETYPE_DODGE: + this.setDodgePoint(buf8, bufWidth, x, y); + break; + + case Neo.Painter.LINETYPE_BURN: + this.setBurnPoint(buf8, bufWidth, x, y); + break; + + default: + break; + } +}; + + +Neo.Painter.prototype.setPenPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_PEN); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + if (a > 0) { + var a1x = Math.max(a1, 1.0/255); + + var r = (r1 * a1x + r0 * a0 * (1 - a1x)) / a; + var g = (g1 * a1x + g0 * a0 * (1 - a1x)) / a; + var b = (b1 * a1x + b0 * a0 * (1 - a1x)) / a; + + r = (r1 > r0) ? Math.ceil(r) : Math.floor(r); + g = (g1 > g0) ? Math.ceil(g) : Math.floor(g); + b = (b1 > b0) ? Math.ceil(b) : Math.floor(b); + } + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setBrushPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + if (a > 0) { + var a1x = Math.max(a1, 1.0/255); + + var r = (r1 * a1x + r0 * a0) / (a0 + a1x); + var g = (g1 * a1x + g0 * a0) / (a0 + a1x); + var b = (b1 * a1x + b0 * a0) / (a0 + a1x); + + r = (r1 > r0) ? Math.ceil(r) : Math.floor(r); + g = (g1 > g0) ? Math.ceil(g) : Math.floor(g); + b = (b1 > b0) ? Math.ceil(b) : Math.floor(b); + } + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setTonePoint = function(buf8, width, x, y, x0, y0) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + + x -= r0; + y -= r0; + x0 -= r0; + y0 -= r0; +// x -= r0; +// y -= r0; +// if (r0%2) { x0++; y0++; } //なぜか模様がずれるので + + var shape = this._roundData[d]; + var shapeIndex = 0; + var index = (y * width + x) * 4; + + var r = this._currentColor[0]; + var g = this._currentColor[1]; + var b = this._currentColor[2]; + var a = this._currentColor[3]; + + var toneData = this.getToneData(a); + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + if (toneData[((y0+i)%4) + (((x0+j)%4) * 4)]) { + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = 255; + } + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setEraserPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var shape = this._roundData[d]; + var shapeIndex = 0; + var index = (y * width + x) * 4; + var a = Math.floor(this.alpha * 255); + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var k = (buf8[index + 3] / 255.0) * (1.0 - (a / 255.0)); + + buf8[index + 3] -= a / (d * (255.0 - a) / 255.0); + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setBlurPoint = function(buf8, width, x, y, x0, y0) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var shape = this._roundData[d]; + var shapeIndex = 0; + var height = buf8.length / (width * 4); + +// var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + var a1 = this.alpha / 12; + if (a1 == 0) return; + var blur = a1; + + var tmp = new Uint8ClampedArray(buf8.length); + for (var i = 0; i < buf8.length; i++) { + tmp[i] = buf8[i]; + } + + var left = x0 - x - r0; + var top = y0 - y - r0; + + var xstart = 0, xend = d; + var ystart = 0, yend = d; + if (xstart > left) xstart = -left; + if (ystart > top) ystart = -top; + if (xend > this.canvasWidth - left) xend = this.canvasWidth - left; + if (yend > this.canvasHeight - top) yend = this.canvasHeight - top; + + for (var j = ystart; j < yend; j++) { + var index = (j * width + xstart) * 4; + for (var i = xstart; i < xend; i++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var rgba = [0, 0, 0, 0, 0]; + + this.addBlur(tmp, index, 1.0 - blur*4, rgba); + if (i > xstart) this.addBlur(tmp, index - 4, blur, rgba); + if (i < xend - 1) this.addBlur(tmp, index + 4, blur, rgba); + if (j > ystart) this.addBlur(tmp, index - width*4, blur, rgba); + if (j < yend - 1) this.addBlur(tmp, index + width*4, blur, rgba); + + buf8[index + 0] = Math.round(rgba[0]); + buf8[index + 1] = Math.round(rgba[1]); + buf8[index + 2] = Math.round(rgba[2]); + buf8[index + 3] = Math.round((rgba[3] / rgba[4]) * 255.0); + } + index += 4; + } + } +}; + +Neo.Painter.prototype.setDodgePoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + if (a1 != 255.0) { + var r1 = r0 * 255 / (255 - a1); + var g1 = g0 * 255 / (255 - a1); + var b1 = b0 * 255 / (255 - a1); + } else { + var r1 = 255.0; + var g1 = 255.0; + var b1 = 255.0; + } + + var r = Math.ceil(r1); + var g = Math.ceil(g1); + var b = Math.ceil(b1); + var a = a0; + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +Neo.Painter.prototype.setBurnPoint = function(buf8, width, x, y) { + var d = this.lineWidth; + var r0 = Math.floor(d / 2); + x -= r0; + y -= r0; + + var index = (y * width + x) * 4; + + var shape = this._roundData[d]; + var shapeIndex = 0; + + var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH); + if (a1 == 0) return; + + for (var i = 0; i < d; i++) { + for (var j = 0; j < d; j++) { + if (shape[shapeIndex++] && !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + if (a1 != 255.0) { + var r1 = 255 - (255 - r0) * 255 / (255 - a1); + var g1 = 255 - (255 - g0) * 255 / (255 - a1); + var b1 = 255 - (255 - b0) * 255 / (255 - a1); + } else { + var r1 = 0; + var g1 = 0; + var b1 = 0; + } + + var r = Math.floor(r1); + var g = Math.floor(g1); + var b = Math.floor(b1); + var a = a0; + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } + index += 4; + } + index += (width - d) * 4; + } +}; + +////////////////////////////////////////////////////////////////////// + +Neo.Painter.prototype.xorPixel = function(buf32, bufWidth, x, y, c) { + var index = y * bufWidth + x; + if (!c) c = 0xffffff; + buf32[index] ^= c; +}; + +Neo.Painter.prototype.getBezierPoint = function(t, x0, y0, x1, y1, x2, y2, x3, y3) { + var a0 = (1 - t) * (1 - t) * (1 - t); + var a1 = (1 - t) * (1 - t) * t * 3; + var a2 = (1 - t) * t * t * 3; + var a3 = t * t * t; + + var x = x0 * a0 + x1 * a1 + x2 * a2 + x3 * a3; + var y = y0 * a0 + y1 * a1 + y2 * a2 + y3 * a3; + return [x, y]; +}; + +var nmax = 1; + +Neo.Painter.prototype.drawBezier = function(ctx, x0, y0, x1, y1, x2, y2, x3, y3, type) { + var xmax = Math.max(x0, x1, x2, x3); + var xmin = Math.min(x0, x1, x2, x3); + var ymax = Math.max(y0, y1, y2, y3); + var ymin = Math.min(y0, y1, y2, y3); + var n = Math.ceil(((xmax - xmin) + (ymax - ymin)) * 2.5); + + if (n > nmax) { + n = (n < nmax * 2) ? n : nmax * 2; + nmax = n; + } + + for (var i = 0; i < n; i++) { + var t = i * 1.0 / n; + var p = this.getBezierPoint(t, x0, y0, x1, y1, x2, y2, x3, y3); + this.drawPoint(ctx, p[0], p[1], type); + } +}; + +Neo.Painter.prototype.prevLine = null; // 始点または終点が2度プロットされることがあるので +Neo.Painter.prototype.drawLine = function(ctx, x0, y0, x1, y1, type) { + x0 = Math.round(x0); + x1 = Math.round(x1); + y0 = Math.round(y0); + y1 = Math.round(y1); + var prev = [x0, y0, x1, y1]; + + var width = Math.abs(x1 - x0); + var height = Math.abs(y1 - y0); + var r = Math.ceil(this.lineWidth / 2); + + var left = ((x0 < x1) ? x0 : x1) - r; + var top = ((y0 < y1) ? y0 : y1) - r; + + var imageData = ctx.getImageData(left, top, width + r*2, height + r*2); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var dx = width, sx = x0 < x1 ? 1 : -1; + var dy = height, sy = y0 < y1 ? 1 : -1; + var err = (dx > dy ? dx : -dy) / 2; + this.aerr = 0; + + while (true) { + if (this.prevLine == null || + !((this.prevLine[0] == x0 && this.prevLine[1] == y0) || + (this.prevLine[2] == x0 && this.prevLine[3] == y0))) { + this.setPoint(buf8, imageData.width, x0, y0, left, top, type); + } + + if (x0 === x1 && y0 === y1) break; + var e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } + + imageData.data.set(buf8); + ctx.putImageData(imageData, left, top); + + this.prevLine = prev; +}; + +Neo.Painter.prototype.drawPoint = function(ctx, x, y, type) { + this.drawLine(ctx, x, y, x, y, type); +}; + +Neo.Painter.prototype.xorRect = function(buf32, bufWidth, x, y, width, height, c) { + var index = y * bufWidth + x; + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + buf32[index] ^= c; + index++; + } + index += width - bufWidth; + } +}; + +Neo.Painter.prototype.drawXORRect = function(ctx, x, y, width, height, isFill, c) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + if (width == 0 || height == 0) return; + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var index = 0; + if (!c) c = 0xffffff; + + if (isFill) { + this.xorRect(buf32, width, 0, 0, width, height, c); + + } else { + for (var i = 0; i < width; i++) { //top + buf32[index] = buf32[index] ^= c; + index++; + } + if (height > 1) { + index = width; + for (var i = 1; i < height; i++) { //left + buf32[index] = buf32[index] ^= c; + index += width; + } + if (width > 1) { + index = width * 2 - 1; + for (var i = 1; i < height - 1; i++) { //right + buf32[index] = buf32[index] ^= c; + index += width; + } + index = width * (height - 1) + 1; + for (var i = 1; i < width; i++) { // bottom + buf32[index] = buf32[index] ^= c; + index++; + } + } + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.drawXOREllipse = function(ctx, x, y, width, height, isFill, c) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + if (width == 0 || height == 0) return; + if (!c) c = 0xffffff; + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + + var a = width-1, b = height-1, b1 = b&1; /* values of diameter */ + var dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */ + var err = dx+dy+b1*a*a, e2; /* error of 1.step */ + + var x0 = x; + var y0 = y; + var x1 = x0+a; + var y1 = y0+b; + + if (x0 > x1) { x0 = x1; x1 += a; } + if (y0 > y1) y0 = y1; + y0 += Math.floor((b+1)/2); y1 = y0-b1; /* starting pixel */ + a *= 8*a; b1 = 8*b*b; + var ymin = y0 - 1; + + do { + if (isFill) { + if (ymin < y0) { + this.xorRect(buf32, width, x0-x, y0 - y, x1 - x0, 1, c); + if (y0 != y1) { + this.xorRect(buf32, width, x0-x, y1 - y, x1 - x0, 1, c); + } + ymin = y0; + } + } else { + this.xorPixel(buf32, width, x1-x, y0-y, c); + if (x0 != x1) { + this.xorPixel(buf32, width, x0-x, y0-y, c); + } + if (y0 != y1) { + this.xorPixel(buf32, width, x0-x, y1-y, c); + if (x0 != x1) { + this.xorPixel(buf32, width, x1-x, y1-y, c); + } + } + } + e2 = 2*err; + if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ + if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */ + } while (x0 <= x1); + + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.drawXORLine = function(ctx, x0, y0, x1, y1, c) { + x0 = Math.round(x0); + x1 = Math.round(x1); + y0 = Math.round(y0); + y1 = Math.round(y1); + + var width = Math.abs(x1 - x0); + var height = Math.abs(y1 - y0); + + var left = ((x0 < x1) ? x0 : x1); + var top = ((y0 < y1) ? y0 : y1); +// console.log("left:"+left+" top:"+top+" width:"+width+" height:"+height); + + var imageData = ctx.getImageData(left, top, width + 1, height + 1); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var dx = width, sx = x0 < x1 ? 1 : -1; + var dy = height, sy = y0 < y1 ? 1 : -1; + var err = (dx > dy ? dx : -dy) / 2; + + while (true) { + if (this.prevLine == null || + !((this.prevLine[0] == x0 && this.prevLine[1] == y0) || + (this.prevLine[2] == x0 && this.prevLine[3] == y0))) { + + this.xorPixel(buf32, imageData.width, x0 - left, y0 - top, c); + } + + if (x0 === x1 && y0 === y1) break; + var e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } + + imageData.data.set(buf8); + ctx.putImageData(imageData, left, top); +}; + + +Neo.Painter.prototype.eraseRect = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var index = 0; + + var a = 1.0 - this.alpha; + if (a != 0) { + a = Math.ceil(2.0 / a); + } else { + a = 255; + } + + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + if (!this.isMasked(buf8, index)) { + buf8[index + 3] -= a; + } + index += 4; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.flipH = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var half = Math.floor(width / 2); + for (var j = 0; j < height; j++) { + var index = j * width; + var index2 = index + (width - 1); + for (var i = 0; i < half; i++) { + var value = buf32[index + i]; + buf32[index + i] = buf32[index2 -i]; + buf32[index2 - i] = value; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.flipV = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var half = Math.floor(height / 2); + for (var j = 0; j < half; j++) { + var index = j * width; + var index2 = (height - 1 - j) * width; + for (var i = 0; i < width; i++) { + var value = buf32[index + i]; + buf32[index + i] = buf32[index2 + i]; + buf32[index2 + i] = value; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.merge = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = []; + var buf32 = []; + var buf8 = []; + for (var i = 0; i < 2; i++) { + imageData[i] = this.canvasCtx[i].getImageData(x, y, width, height); + buf32[i] = new Uint32Array(imageData[i].data.buffer); + buf8[i] = new Uint8ClampedArray(imageData[i].data.buffer); + } + + var dst = this.current; + var src = (dst == 1) ? 0 : 1; + var size = width * height; + var index = 0; + for (var i = 0; i < size; i++) { + var r0 = buf8[0][index + 0]; + var g0 = buf8[0][index + 1]; + var b0 = buf8[0][index + 2]; + var a0 = buf8[0][index + 3] / 255.0; + var r1 = buf8[1][index + 0]; + var g1 = buf8[1][index + 1]; + var b1 = buf8[1][index + 2]; + var a1 = buf8[1][index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + if (a > 0) { + var r = Math.floor((r1 * a1 + r0 * a0 * (1 - a1)) / a + 0.5); + var g = Math.floor((g1 * a1 + g0 * a0 * (1 - a1)) / a + 0.5); + var b = Math.floor((b1 * a1 + b0 * a0 * (1 - a1)) / a + 0.5); + } + buf8[src][index + 0] = 0; + buf8[src][index + 1] = 0; + buf8[src][index + 2] = 0; + buf8[src][index + 3] = 0; + buf8[dst][index + 0] = r; + buf8[dst][index + 1] = g; + buf8[dst][index + 2] = b; + buf8[dst][index + 3] = Math.floor(a * 255 + 0.5); + index += 4; + } + + for (var i = 0; i < 2; i++) { + imageData[i].data.set(buf8[i]); + this.canvasCtx[i].putImageData(imageData[i], x, y); + } +}; + +Neo.Painter.prototype.blurRect = function(ctx, x, y, width, height) { + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var tmp = new Uint8ClampedArray(buf8.length); + for (var i = 0; i < buf8.length; i++) tmp[i] = buf8[i]; + + var index = 0; + var a1 = this.alpha / 12; + var blur = a1; + + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + var rgba = [0, 0, 0, 0, 0]; + + this.addBlur(tmp, index, 1.0 - blur*4, rgba); + + if (i > 0) this.addBlur(tmp, index - 4, blur, rgba); + if (i < width - 1) this.addBlur(tmp, index + 4, blur, rgba); + if (j > 0) this.addBlur(tmp, index - width*4, blur, rgba); + if (j < height - 1) this.addBlur(tmp, index + width*4, blur, rgba); + + var w = rgba[4]; + buf8[index + 0] = Math.round(rgba[0]); + buf8[index + 1] = Math.round(rgba[1]); + buf8[index + 2] = Math.round(rgba[2]); + buf8[index + 3] = Math.ceil((rgba[3] / w) * 255.0); + + index += 4; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.addBlur = function(buffer, index, a, rgba) { + var r0 = rgba[0]; + var g0 = rgba[1]; + var b0 = rgba[2]; + var a0 = rgba[3]; + var r1 = buffer[index + 0]; + var g1 = buffer[index + 1]; + var b1 = buffer[index + 2]; + var a1 = (buffer[index + 3] / 255.0) * a; + rgba[4] += a; + + var a = a0 + a1; + if (a > 0) { + rgba[0] = (r1 * a1 + r0 * a0) / (a0 + a1); + rgba[1] = (g1 * a1 + g0 * a0) / (a0 + a1); + rgba[2] = (b1 * a1 + b0 * a0) / (a0 + a1); + rgba[3] = a; + } +}; + +Neo.Painter.prototype.pickColor = function(x, y) { + var r = 0xff, g = 0xff, b = 0xff, a; + + x = Math.floor(x); + y = Math.floor(y); + if (x >= 0 && x < this.canvasWidth && + y >= 0 && y < this.canvasHeight) { + + for (var i = 0; i < 2; i++) { + if (this.visible[i]) { + var ctx = this.canvasCtx[i]; + var imageData = ctx.getImageData(x, y, 1, 1); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var a = buf8[3] / 255.0; + r = r * (1.0 - a) + buf8[2] * a; + g = g * (1.0 - a) + buf8[1] * a; + b = b * (1.0 - a) + buf8[0] * a; + } + } + r = Math.max(Math.min(Math.round(r), 255), 0); + g = Math.max(Math.min(Math.round(g), 255), 0); + b = Math.max(Math.min(Math.round(b), 255), 0); + var result = r | g<<8 | b<<16; + } + this.setColor(result); + + + if (this.current > 0) { + if (a == 0 && (result == 0xffffff || this.getEmulationMode() < 2.16)) { + this.setToolByType(Neo.eraserTip.tools[Neo.eraserTip.mode]); + + } else { + if (Neo.eraserTip.selected) { + this.setToolByType(Neo.penTip.tools[Neo.penTip.mode]); + } + } + } +}; + +Neo.Painter.prototype.fillHorizontalLine = function(buf32, x0, x1, y) { + var index = y * this.canvasWidth + x0; + var fillColor = this.getColor(); + for (var x = x0; x <= x1; x++) { + buf32[index++] = fillColor; + } +}; + +Neo.Painter.prototype.scanLine = function(x0, x1, y, baseColor, buf32, stack) { + var width = this.canvasWidth; + for (var x = x0; x <= x1; x++) { + stack.push({x:x, y: y}) + } +/* + while (x0 <= x1) { + for (; x0 <= x1; x0++) { + if (buf32[y * width + x0] == baseColor) break; + } + if (x1 < x0) break; + + for (; x0 <= x1; x0++) { + if (buf32[y * width + x0] != baseColor) break; + } + stack.push({x:x0 - 1, y: y}) + } +*/ +}; + +Neo.Painter.prototype.fill = function(x, y, ctx) { + x = Math.round(x); + y = Math.round(y); + + if (x < 0 || x >= this.canvasWidth || y < 0 || y >= this.canvasHeight) { + return; + } + + var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var width = imageData.width; + var stack = [{x: x, y: y}]; + + var baseColor = buf32[y * width + x]; + var fillColor = this.getColor(); + + if ((baseColor & 0xff000000) == 0 || (baseColor != fillColor)) { + while (stack.length > 0) { + if (stack.length > 1000000) { + console.log('too much stack') + break; + } + var point = stack.pop(); + var x = point.x; + var y = point.y; + var x0 = x; + var x1 = x; + if (buf32[y * width + x] == fillColor) continue; + if (buf32[y * width + x] != baseColor) continue; + + for (; 0 < x0; x0--) { + if (buf32[y * width + (x0 - 1)] != baseColor) break; + } + for (; x1 < this.canvasWidth - 1; x1++) { + if (buf32[y * width + (x1 + 1)] != baseColor) break; + } + this.fillHorizontalLine(buf32, x0, x1, y); + + if (y + 1 < this.canvasHeight) { + this.scanLine(x0, x1, y + 1, baseColor, buf32, stack); + } + if (y - 1 >= 0) { + this.scanLine(x0, x1, y - 1, baseColor, buf32, stack); + } + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype.copy = function(x, y, width, height) { + this.tempX = 0; + this.tempY = 0; + this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + + var imageData = this.canvasCtx[this.current].getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + this.temp = new Uint32Array(buf32.length); + for (var i = 0; i < buf32.length; i++) { + this.temp[i] = buf32[i]; + } + + //tempCanvasに乗せる画像を作る + imageData = this.tempCanvasCtx.getImageData(x, y, width, height); + buf32 = new Uint32Array(imageData.data.buffer); + buf8 = new Uint8ClampedArray(imageData.data.buffer); + for (var i = 0; i < buf32.length; i++) { + if (this.temp[i] >> 24) { + buf32[i] = this.temp[i] | 0xff000000; + } else { + buf32[i] = 0xffffffff; + } + } + imageData.data.set(buf8); + this.tempCanvasCtx.putImageData(imageData, x, y); +}; + + +Neo.Painter.prototype.paste = function(x, y, width, height) { + var ctx = this.canvasCtx[this.current]; +// console.log(this.tempX, this.tempY); + + var imageData = ctx.getImageData(x + this.tempX, y + this.tempY, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + for (var i = 0; i < buf32.length; i++) { + buf32[i] = this.temp[i]; + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x + this.tempX, y + this.tempY); + + this.temp = null; + this.tempX = 0; + this.tempY = 0; + this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype.turn = function(x, y, width, height) { + var ctx = this.canvasCtx[this.current]; + + // 傾けツールのバグを再現するため一番上のラインで対象領域を埋める + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var temp = new Uint32Array(buf32.length); + + var index = 0; + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + temp[index] = buf32[index]; + if (index >= width) { + buf32[index] = buf32[index % width]; + } + index++; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); + + // 90度回転させて貼り付け + imageData = ctx.getImageData(x, y, height, width); + buf32 = new Uint32Array(imageData.data.buffer); + buf8 = new Uint8ClampedArray(imageData.data.buffer); + + index = 0; + for (var j = height - 1; j >= 0; j--) { + for (var i = 0; i < width; i++) { + buf32[i * height + j] = temp[index++]; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.doFill = function(ctx, x, y, width, height, maskFunc) { + if (Math.round(x) != x) console.log("*"); + if (Math.round(width) != width) console.log("*"); + if (Math.round(height) != height) console.log("*"); + + var imageData = ctx.getImageData(x, y, width, height); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + var index = 0; + + var r1 = this._currentColor[0]; + var g1 = this._currentColor[1]; + var b1 = this._currentColor[2]; + var a1 = this.getAlpha(Neo.ALPHATYPE_FILL); + + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + if (maskFunc && maskFunc.call(this, i, j, width, height)) { + //なぜか加算逆加算は適用されない + if (this.maskType >= Neo.Painter.MASKTYPE_ADD || + !this.isMasked(buf8, index)) { + var r0 = buf8[index + 0]; + var g0 = buf8[index + 1]; + var b0 = buf8[index + 2]; + var a0 = buf8[index + 3] / 255.0; + + var a = a0 + a1 - a0 * a1; + + if (a > 0) { + var a1x = a1; + var ax = 1 + a0 * (1 - a1x); + + var r = (r1 + r0 * a0 * (1 - a1x)) / ax; + var g = (g1 + g0 * a0 * (1 - a1x)) / ax; + var b = (b1 + b0 * a0 * (1 - a1x)) / ax + + r = (r1 > r0) ? Math.ceil(r) : Math.floor(r); + g = (g1 > g0) ? Math.ceil(g) : Math.floor(g); + b = (b1 > b0) ? Math.ceil(b) : Math.floor(b); + } + + var tmp = a * 255; + a = Math.ceil(tmp); + + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + } + } + index += 4; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, x, y); +}; + +Neo.Painter.prototype.rectFillMask = function(x, y, width, height) { + return true; +}; + +Neo.Painter.prototype.rectMask = function(x, y, width, height) { + var d = this.lineWidth; + return (x < d || x > width - 1 - d || + y < d || y > height - 1 - d) ? true : false; +}; + +Neo.Painter.prototype.ellipseFillMask = function(x, y, width, height) { + var cx = (width - 1) / 2.0; + var cy = (height - 1) / 2.0; + x = (x - cx) / (cx + 1); + y = (y - cy) / (cy + 1); + + return ((x * x) + (y * y) < 1) ? true : false; +} + +Neo.Painter.prototype.ellipseMask = function(x, y, width, height) { + var d = this.lineWidth; + var cx = (width - 1) / 2.0; + var cy = (height - 1) / 2.0; + + if (cx <= d || cy <= d) return this.ellipseFillMask(x, y, width, height); + + var x2 = (x - cx) / (cx - d + 1); + var y2 = (y - cy) / (cy - d + 1); + + x = (x - cx) / (cx + 1); + y = (y - cy) / (cy + 1); + + if ((x * x) + (y * y) < 1) { + if ((x2 * x2) + (y2 * y2) >= 1) { + return true; + } + } + return false; +} + +/* +----------------------------------------------------------------------- +*/ + +Neo.Painter.prototype.getDestCanvasPosition = function(mx, my, isClip, isCenter) { + var mx = Math.floor(mx); //Math.round(mx); + var my = Math.floor(my); //Math.round(my); + if (isCenter) { + mx += 0.499; + my += 0.499; + } + var x = (mx - this.zoomX + this.destCanvas.width * 0.5 / this.zoom) * this.zoom; + var y = (my - this.zoomY + this.destCanvas.height * 0.5 / this.zoom) * this.zoom; + + if (isClip) { + x = Math.max(Math.min(x, this.destCanvas.width), 0); + y = Math.max(Math.min(y, this.destCanvas.height), 0); + } + return {x:x, y:y}; +}; + +Neo.Painter.prototype.isWidget = function(element) { + while (1) { + if (element == null || + element.id == "canvas" || + element.id == "container") break; + + if (element.id == "tools" || + element.className == "buttonOn" || + element.className == "buttonOff" || + element.className == "inputText") { + return true; + } + element = element.parentNode; + } + return false; +}; + +Neo.Painter.prototype.isContainer = function(element) { + while (1) { + if (element == null) break; + if (element.id == "container") return true; + element = element.parentNode; + } + return false; +}; + +Neo.Painter.prototype.cancelTool = function(e) { + if (this.tool) { + this.isMouseDown = false; + this.tool.upHandler(this); + +// switch (this.tool.type) { +// case Neo.Painter.TOOLTYPE_HAND: +// case Neo.Painter.TOOLTYPE_SLIDER: +// this.isMouseDown = false; +// this.tool.upHandler(this); +// } + } +}; + +Neo.Painter.prototype.loadImage = function (filename) { + console.log("loadImage " + filename); + var img = new Image(); + img.src = filename; + img.onload = function() { + var oe = Neo.painter; + oe.canvasCtx[0].drawImage(img, 0, 0); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight); + }; +}; + +Neo.Painter.prototype.loadSession = function (filename) { + if (Neo.storage) { + var img0 = new Image(); + img0.src = Neo.storage.getItem('layer0'); + img0.onload = function() { + var img1 = new Image(); + img1.src = Neo.storage.getItem('layer1'); + img1.onload = function() { + var oe = Neo.painter; + oe.canvasCtx[0].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.canvasCtx[1].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.canvasCtx[0].drawImage(img0, 0, 0); + oe.canvasCtx[1].drawImage(img1, 0, 0); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight); + } + } + } +}; + +Neo.Painter.prototype.saveSession = function() { + if (Neo.storage) { + Neo.storage.setItem('timestamp', +(new Date())); + Neo.storage.setItem('layer0', this.canvas[0].toDataURL('image/png')); + Neo.storage.setItem('layer1', this.canvas[1].toDataURL('image/png')); + } +}; + +Neo.Painter.prototype.clearSession = function() { + if (Neo.storage) { + Neo.storage.removeItem('timestamp'); + Neo.storage.removeItem('layer0'); + Neo.storage.removeItem('layer1'); + } +}; + +Neo.Painter.prototype.sortColor = function(r0, g0, b0) { + var min = (r0 < g0) ? ((r0 < b0) ? 0 : 2) : ((g0 < b0) ? 1 : 2); + var max = (r0 > g0) ? ((r0 > b0) ? 0 : 2) : ((g0 > b0) ? 1 : 2); + var mid = (min + max == 1) ? 2 : ((min + max == 2) ? 1 : 0); + return [min, mid, max]; +}; + +Neo.Painter.prototype.doText = function(x, y, string, fontSize) { + //テキスト描画 + //描画位置がずれるので適当に調整 + var offset = parseInt(fontSize, 10); +// y -= Math.round((5.0 + offset/8) / this.zoom); +// x += Math.round(2.0 / this.zoom); + + var ctx = this.tempCanvasCtx; + ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); + ctx.save(); + ctx.translate(x, y); +// ctx.scale(1/this.zoom, 1/this.zoom); + + var fontFamily = Neo.painter.inputText.style.fontFamily || "Arial"; + ctx.font = fontSize + " " + fontFamily; + + ctx.fillStyle = 0; + ctx.fillText(string, 0, 0); + ctx.restore(); + + // 適当に二値化 + var c = this.getColor(); + var r = c & 0xff; + var g = (c & 0xff00) >> 8; + var b = (c & 0xff0000) >> 16; + var a = Math.round(this.alpha * 255.0); + + var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var length = this.canvasWidth * this.canvasHeight; + var index = 0; + for (var i = 0; i < length; i++) { + if (buf8[index + 3] >= 0x60) { + buf8[index + 0] = r; + buf8[index + 1] = g; + buf8[index + 2] = b; + buf8[index + 3] = a; + + } else { + buf8[index + 0] = 0; + buf8[index + 1] = 0; + buf8[index + 2] = 0; + buf8[index + 3] = 0; + } + index += 4; + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + + //キャンバスに貼り付け + ctx = this.canvasCtx[this.current]; + ctx.globalAlpha = 1.0; + ctx.drawImage(this.tempCanvas, + 0, 0, this.canvasWidth, this.canvasHeight, + 0, 0, this.canvasWidth, this.canvasHeight); + + this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); +}; + +Neo.Painter.prototype.isUIPaused = function() { + if (this.drawType == Neo.Painter.DRAWTYPE_BEZIER) { + if (this.tool.step && this.tool.step > 0) { + return true; + } + } + return false; +}; + +Neo.Painter.prototype.getEmulationMode = function() { + return parseFloat(Neo.config.neo_emulation_mode || 2.22) +}; + +'use strict'; + +Neo.ToolBase = function() {}; + +Neo.ToolBase.prototype.startX; +Neo.ToolBase.prototype.startY; +Neo.ToolBase.prototype.init = function(oe) {} +Neo.ToolBase.prototype.kill = function(oe) {} +Neo.ToolBase.prototype.lineType = Neo.Painter.LINETYPE_NONE; + +Neo.ToolBase.prototype.downHandler = function(oe) { + this.startX = oe.mouseX; + this.startY = oe.mouseY; +}; + +Neo.ToolBase.prototype.upHandler = function(oe) { +}; + +Neo.ToolBase.prototype.moveHandler = function(oe) { +}; + +Neo.ToolBase.prototype.transformForZoom = function(oe) { + var ctx = oe.destCanvasCtx; + ctx.translate(oe.canvasWidth * 0.5, oe.canvasHeight * 0.5); + ctx.scale(oe.zoom, oe.zoom); + ctx.translate(-oe.zoomX, -oe.zoomY); +}; + +Neo.ToolBase.prototype.getType = function() { + return this.type; +}; + +Neo.ToolBase.prototype.getToolButton = function() { + switch (this.type) { + case Neo.Painter.TOOLTYPE_PEN: + case Neo.Painter.TOOLTYPE_BRUSH: + case Neo.Painter.TOOLTYPE_TEXT: + return Neo.penTip; + + case Neo.Painter.TOOLTYPE_TONE: + case Neo.Painter.TOOLTYPE_BLUR: + case Neo.Painter.TOOLTYPE_DODGE: + case Neo.Painter.TOOLTYPE_BURN: + return Neo.pen2Tip; + + case Neo.Painter.TOOLTYPE_RECT: + case Neo.Painter.TOOLTYPE_RECTFILL: + case Neo.Painter.TOOLTYPE_ELLIPSE: + case Neo.Painter.TOOLTYPE_ELLIPSEFILL: + return Neo.effectTip; + + case Neo.Painter.TOOLTYPE_COPY: + case Neo.Painter.TOOLTYPE_MERGE: + case Neo.Painter.TOOLTYPE_BLURRECT: + case Neo.Painter.TOOLTYPE_FLIP_H: + case Neo.Painter.TOOLTYPE_FLIP_V: + case Neo.Painter.TOOLTYPE_TURN: + return Neo.effect2Tip; + + case Neo.Painter.TOOLTYPE_ERASER: + case Neo.Painter.TOOLTYPE_ERASEALL: + case Neo.Painter.TOOLTYPE_ERASERECT: + return Neo.eraserTip; + + case Neo.Painter.TOOLTYPE_FILL: + return Neo.fillButton; + } + return null; +}; + +Neo.ToolBase.prototype.getReserve = function() { + switch (this.type) { + case Neo.Painter.TOOLTYPE_ERASER: + return Neo.reserveEraser; + + case Neo.Painter.TOOLTYPE_PEN: + case Neo.Painter.TOOLTYPE_BRUSH: + case Neo.Painter.TOOLTYPE_TONE: + case Neo.Painter.TOOLTYPE_ERASERECT: + case Neo.Painter.TOOLTYPE_ERASEALL: + case Neo.Painter.TOOLTYPE_COPY: + case Neo.Painter.TOOLTYPE_MERGE: + case Neo.Painter.TOOLTYPE_FIP_H: + case Neo.Painter.TOOLTYPE_FIP_V: + + case Neo.Painter.TOOLTYPE_DODGE: + case Neo.Painter.TOOLTYPE_BURN: + case Neo.Painter.TOOLTYPE_BLUR: + case Neo.Painter.TOOLTYPE_BLURRECT: + + case Neo.Painter.TOOLTYPE_TEXT: + case Neo.Painter.TOOLTYPE_TURN: + case Neo.Painter.TOOLTYPE_RECT: + case Neo.Painter.TOOLTYPE_RECTFILL: + case Neo.Painter.TOOLTYPE_ELLIPSE: + case Neo.Painter.TOOLTYPE_ELLIPSEFILL: + return Neo.reservePen; + + } + return null; +}; + +Neo.ToolBase.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.updateUI(); + } +}; + +Neo.ToolBase.prototype.saveStates = function() { + var reserve = this.getReserve(); + if (reserve) { + reserve.size = Neo.painter.lineWidth; + } +}; + +/* + ------------------------------------------------------------------------- + DrawToolBase(描画ツールのベースクラス) + ------------------------------------------------------------------------- +*/ + +Neo.DrawToolBase = function() {}; +Neo.DrawToolBase.prototype = new Neo.ToolBase(); +Neo.DrawToolBase.prototype.isUpMove = false; +Neo.DrawToolBase.prototype.step = 0; + +Neo.DrawToolBase.prototype.init = function() { + this.step = 0; + this.isUpMove = true; +}; + +Neo.DrawToolBase.prototype.downHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandDownHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineDownHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierDownHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.upHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandUpHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineUpHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierUpHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.moveHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierMoveHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.upMoveHandler = function(oe) { + switch (oe.drawType) { + case Neo.Painter.DRAWTYPE_FREEHAND: + this.freeHandUpMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_LINE: + this.lineUpMoveHandler(oe); break; + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierUpMoveHandler(oe); break; + } +}; + +Neo.DrawToolBase.prototype.keyDownHandler = function(e) { + switch (Neo.painter.drawType) { + case Neo.Painter.DRAWTYPE_BEZIER: + this.bezierKeyDownHandler(e); break; + } +}; + +Neo.DrawToolBase.prototype.rollOverHandler= function(oe) {}; +Neo.DrawToolBase.prototype.rollOutHandler= function(oe) { + if (!oe.isMouseDown && !oe.isMouseDownRight){ + oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + } +}; + +Neo.DrawToolBase.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 1.0; + Neo.updateUI(); + }; +}; + + +/* FreeHand (手書き) */ + +Neo.DrawToolBase.prototype.freeHandDownHandler = function(oe) { + //Register undo first; + oe._pushUndo(); + + oe.prepareDrawing(); + this.isUpMove = false; + var ctx = oe.canvasCtx[oe.current]; + if (oe.alpha >= 1 || this.lineType != Neo.Painter.LINETYPE_BRUSH) { + var x0 = Math.floor(oe.mouseX); + var y0 = Math.floor(oe.mouseY); + oe.drawLine(ctx, x0, y0, x0, y0, this.lineType); + } + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + + if (oe.alpha >= 1) { + var r = Math.ceil(oe.lineWidth / 2); + var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.mouseX, oe.mouseY, r); + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + } +}; + +Neo.DrawToolBase.prototype.freeHandUpHandler = function(oe) { + oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight); + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + + // oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + // this.drawCursor(oe); + oe.prevLine = null; +}; + +Neo.DrawToolBase.prototype.freeHandMoveHandler = function(oe) { + var ctx = oe.canvasCtx[oe.current]; + var x0 = Math.floor(oe.mouseX); + var y0 = Math.floor(oe.mouseY); + var x1 = Math.floor(oe.prevMouseX); + var y1 = Math.floor(oe.prevMouseY); + oe.drawLine(ctx, x0, y0, x1, y1, this.lineType); + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + + var r = Math.ceil(oe.lineWidth / 2); + var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.prevMouseX, oe.prevMouseY, r); + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); +}; + +Neo.DrawToolBase.prototype.freeHandUpMoveHandler = function(oe) { + this.isUpMove = true; + + if (oe.cursorRect) { + var rect = oe.cursorRect; + oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true); + oe.cursorRect = null; + } + this.drawCursor(oe); +}; + +Neo.DrawToolBase.prototype.drawCursor = function(oe) { + if (oe.lineWidth <= 8) return; + var mx = oe.mouseX; + var my = oe.mouseY; + var d = oe.lineWidth; + + var x = (mx - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom; + var y = (my - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom; + var r = d * 0.5 * oe.zoom; + + if (!(x > -r && + y > -r && + x < oe.destCanvas.width + r && + y < oe.destCanvas.height + r)) return; + + var ctx = oe.destCanvasCtx; + ctx.save(); + this.transformForZoom(oe) + + var c = (this.type == Neo.Painter.TOOLTYPE_ERASER) ? 0x0000ff : 0xffff7f; + oe.drawXOREllipse(ctx, x-r, y-r, r*2, r*2, false, c); + + ctx.restore(); + oe.cursorRect = oe.getBound(mx, my, mx, my, Math.ceil(d / 2)); +} + + +/* Line (直線) */ + +Neo.DrawToolBase.prototype.lineDownHandler = function(oe) { + this.isUpMove = false; + this.startX = Math.floor(oe.mouseX); + this.startY = Math.floor(oe.mouseY); + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); +}; + +Neo.DrawToolBase.prototype.lineUpHandler = function(oe) { + if (this.isUpMove == false) { + this.isUpMove = true; + + oe._pushUndo(); + oe.prepareDrawing(); + var ctx = oe.canvasCtx[oe.current]; + var x0 = Math.floor(oe.mouseX); + var y0 = Math.floor(oe.mouseY); + oe.drawLine(ctx, x0, y0, this.startX, this.startY, this.lineType); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + } +}; + +Neo.DrawToolBase.prototype.lineMoveHandler = function(oe) { + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + this.drawLineCursor(oe); +}; + +Neo.DrawToolBase.prototype.lineUpMoveHandler = function(oe) { +}; + +Neo.DrawToolBase.prototype.drawLineCursor = function(oe, mx, my) { + if (!mx) mx = Math.floor(oe.mouseX); + if (!my) my = Math.floor(oe.mouseY); + var nx = this.startX; + var ny = this.startY; + var ctx = oe.destCanvasCtx; + ctx.save(); + this.transformForZoom(oe) + + var x0 = (mx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom; + var y0 = (my +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom; + var x1 = (nx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom; + var y1 = (ny +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom; + oe.drawXORLine(ctx, x0, y0, x1, y1); + + ctx.restore(); +}; + + +/* Bezier (BZ曲線) */ + +Neo.DrawToolBase.prototype.bezierDownHandler = function(oe) { + this.isUpMove = false; + + if (this.step == 0) { + this.startX = this.x0 = Math.floor(oe.mouseX); + this.startY = this.y0 = Math.floor(oe.mouseY); + } + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); +}; + +Neo.DrawToolBase.prototype.bezierUpHandler = function(oe) { + if (this.isUpMove == false) { + this.isUpMove = true; + } + + this.step++; + switch (this.step) { + case 1: + oe.prepareDrawing(); + this.x3 = Math.floor(oe.mouseX); + this.y3 = Math.floor(oe.mouseY); + break; + + case 2: + this.x1 = Math.floor(oe.mouseX); + this.y1 = Math.floor(oe.mouseY); + break; + + case 3: + this.x2 = Math.floor(oe.mouseX); + this.y2 = Math.floor(oe.mouseY); + + oe._pushUndo(); + oe.drawBezier(oe.canvasCtx[oe.current], + this.x0, this.y0, this.x1, this.y1, + this.x2, this.y2, this.x3, this.y3, this.lineType); + + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + this.step = 0; + break; + + default: + this.step = 0; + break; + } +}; + +Neo.DrawToolBase.prototype.bezierMoveHandler = function(oe) { + switch (this.step) { + case 0: + if (!this.isUpMove) { + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false); + this.drawLineCursor(oe); + } + break; + case 1: + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false); + this.drawBezierCursor1(oe); + break; + + case 2: + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false); + this.drawBezierCursor2(oe); + break; + } +}; + +Neo.DrawToolBase.prototype.bezierUpMoveHandler = function(oe) { + this.bezierMoveHandler(oe); +}; + +Neo.DrawToolBase.prototype.bezierKeyDownHandler = function(e) { + if (e.keyCode == 27) { //Escでキャンセル + this.step = 0; + + var oe = Neo.painter; + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + } +}; + + +Neo.DrawToolBase.prototype.drawBezierCursor1 = function(oe) { + var ctx = oe.destCanvasCtx; + // var x = oe.mouseX; //Math.floor(oe.mouseX); + // var y = oe.mouseY; //Math.floor(oe.mouseY); + var stab = oe.getStabilized(); + var x = Math.floor(stab[0]); + var y = Math.floor(stab[1]); + var p = oe.getDestCanvasPosition(x, y, false, true); + var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true); + var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true); + + // handle + oe.drawXORLine(ctx, p0.x, p0.y, p.x, p.y); + oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8); + oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8); + + // preview + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.drawBezier(oe.tempCanvasCtx, + this.x0, this.y0, + x, y, + x, y, + this.x3, this.y3, this.lineType); + + ctx.save(); + ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5); + ctx.scale(oe.zoom, oe.zoom); + ctx.translate(-oe.zoomX, -oe.zoomY); + ctx.drawImage(oe.tempCanvas, + 0, 0, oe.canvasWidth, oe.canvasHeight, + 0, 0, oe.canvasWidth, oe.canvasHeight); + + ctx.restore(); +}; + +Neo.DrawToolBase.prototype.drawBezierCursor2 = function(oe) { + var ctx = oe.destCanvasCtx; + // var x = oe.mouseX; //Math.floor(oe.mouseX); + // var y = oe.mouseY; //Math.floor(oe.mouseY); + var stab = oe.getStabilized(); + var x = Math.floor(stab[0]); + var y = Math.floor(stab[1]); + var p = oe.getDestCanvasPosition(oe.mouseX, oe.mouseY, false, true); + var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true); + var p1 = oe.getDestCanvasPosition(this.x1, this.y1, false, true); + var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true); + + // handle + oe.drawXORLine(ctx, p3.x, p3.y, p.x, p.y); + oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8); + oe.drawXORLine(ctx, p0.x, p0.y, p1.x, p1.y); + oe.drawXOREllipse(ctx, p1.x - 4, p1.y - 4, 8, 8); + oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8); + + // preview + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.drawBezier(oe.tempCanvasCtx, + this.x0, this.y0, + this.x1, this.y1, + x, y, + this.x3, this.y3, this.lineType); + + ctx.save(); + ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5); + ctx.scale(oe.zoom, oe.zoom); + ctx.translate(-oe.zoomX, -oe.zoomY); + ctx.drawImage(oe.tempCanvas, + 0, 0, oe.canvasWidth, oe.canvasHeight, + 0, 0, oe.canvasWidth, oe.canvasHeight); + ctx.restore(); +}; + +/* + ------------------------------------------------------------------------- + Pen(鉛筆) + ------------------------------------------------------------------------- +*/ + +Neo.PenTool = function() {}; +Neo.PenTool.prototype = new Neo.DrawToolBase(); +Neo.PenTool.prototype.type = Neo.Painter.TOOLTYPE_PEN; +Neo.PenTool.prototype.lineType = Neo.Painter.LINETYPE_PEN; + +Neo.PenTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 1.0; + Neo.updateUI(); + }; +} + +/* + ------------------------------------------------------------------------- + Brush(水彩) + ------------------------------------------------------------------------- +*/ + +Neo.BrushTool = function() {}; +Neo.BrushTool.prototype = new Neo.DrawToolBase(); +Neo.BrushTool.prototype.type = Neo.Painter.TOOLTYPE_BRUSH; +Neo.BrushTool.prototype.lineType = Neo.Painter.LINETYPE_BRUSH; + +Neo.BrushTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = this.getAlpha(); + Neo.updateUI(); + } +}; + +Neo.BrushTool.prototype.getAlpha = function() { + var alpha = 241 - Math.floor(Neo.painter.lineWidth / 2) * 6; + return alpha / 255.0; +}; + +/* + ------------------------------------------------------------------------- + Tone(トーン) + ------------------------------------------------------------------------- +*/ + +Neo.ToneTool = function() {}; +Neo.ToneTool.prototype = new Neo.DrawToolBase(); +Neo.ToneTool.prototype.type = Neo.Painter.TOOLTYPE_TONE; +Neo.ToneTool.prototype.lineType = Neo.Painter.LINETYPE_TONE; + +Neo.ToneTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 23 / 255.0; + Neo.updateUI(); + } +}; + +/* + ------------------------------------------------------------------------- + Eraser(消しペン) + ------------------------------------------------------------------------- +*/ + +Neo.EraserTool = function() {}; +Neo.EraserTool.prototype = new Neo.DrawToolBase(); +Neo.EraserTool.prototype.type = Neo.Painter.TOOLTYPE_ERASER; +Neo.EraserTool.prototype.lineType = Neo.Painter.LINETYPE_ERASER; + + +/* + ------------------------------------------------------------------------- + Blur(ぼかし) + ------------------------------------------------------------------------- +*/ + +Neo.BlurTool = function() {}; +Neo.BlurTool.prototype = new Neo.DrawToolBase(); +Neo.BlurTool.prototype.type = Neo.Painter.TOOLTYPE_BLUR; +Neo.BlurTool.prototype.lineType = Neo.Painter.LINETYPE_BLUR; + +Neo.BlurTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 128 / 255.0; + Neo.updateUI(); + } +}; + +/* + ------------------------------------------------------------------------- + Dodge(覆い焼き) + ------------------------------------------------------------------------- +*/ + +Neo.DodgeTool = function() {}; +Neo.DodgeTool.prototype = new Neo.DrawToolBase(); +Neo.DodgeTool.prototype.type = Neo.Painter.TOOLTYPE_DODGE; +Neo.DodgeTool.prototype.lineType = Neo.Painter.LINETYPE_DODGE; + +Neo.DodgeTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 128 / 255.0; + Neo.updateUI(); + } +}; + +/* + ------------------------------------------------------------------------- + Burn(焼き込み) + ------------------------------------------------------------------------- +*/ + +Neo.BurnTool = function() {}; +Neo.BurnTool.prototype = new Neo.DrawToolBase(); +Neo.BurnTool.prototype.type = Neo.Painter.TOOLTYPE_BURN; +Neo.BurnTool.prototype.lineType = Neo.Painter.LINETYPE_BURN; + +Neo.BurnTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 128 / 255.0; + Neo.updateUI(); + } +}; + +/* + ------------------------------------------------------------------------- + Hand(スクロール) + ------------------------------------------------------------------------- +*/ + +Neo.HandTool = function() {}; +Neo.HandTool.prototype = new Neo.ToolBase(); +Neo.HandTool.prototype.type = Neo.Painter.TOOLTYPE_HAND; +Neo.HandTool.prototype.isUpMove = false; +Neo.HandTool.prototype.reverse = false; + +Neo.HandTool.prototype.downHandler = function(oe) { + oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + + this.isDrag = true; + this.startX = oe.rawMouseX; + this.startY = oe.rawMouseY; +}; + +Neo.HandTool.prototype.upHandler = function(oe) { + this.isDrag = false; + oe.popTool(); +}; + +Neo.HandTool.prototype.moveHandler = function(oe) { + if (this.isDrag) { + var dx = this.startX - oe.rawMouseX; + var dy = this.startY - oe.rawMouseY; + + var ax = oe.destCanvas.width / (oe.canvasWidth * oe.zoom); + var ay = oe.destCanvas.height / (oe.canvasHeight * oe.zoom); + var barWidth = oe.destCanvas.width * ax; + var barHeight = oe.destCanvas.height * ay; + var scrollWidthInScreen = oe.destCanvas.width - barWidth - 2; + var scrollHeightInScreen = oe.destCanvas.height - barHeight - 2; + + dx *= oe.scrollWidth / scrollWidthInScreen; + dy *= oe.scrollHeight / scrollHeightInScreen; + + if (this.reverse) { + dx *= -1; + dy *= -1; + } + + oe.setZoomPosition(oe.zoomX - dx, oe.zoomY - dy); + + this.startX = oe.rawMouseX; + this.startY = oe.rawMouseY; + } +}; + +Neo.HandTool.prototype.upMoveHandler = function(oe) {} +Neo.HandTool.prototype.rollOverHandler= function(oe) {} +Neo.HandTool.prototype.rollOutHandler= function(oe) {}; + +/* + ------------------------------------------------------------------------- + Slider(色やサイズのスライダを操作している時) + ------------------------------------------------------------------------- +*/ + +Neo.SliderTool = function() {}; +Neo.SliderTool.prototype = new Neo.ToolBase(); +Neo.SliderTool.prototype.type = Neo.Painter.TOOLTYPE_SLIDER; +Neo.SliderTool.prototype.isUpMove = false; +Neo.SliderTool.prototype.alt = false; + +Neo.SliderTool.prototype.downHandler = function(oe) { + if (!oe.isShiftDown) this.isDrag = true; + + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + + var rect = this.target.getBoundingClientRect(); + var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider']; + Neo.sliders[sliderType].downHandler(oe.rawMouseX - rect.left, + oe.rawMouseY - rect.top); +}; + +Neo.SliderTool.prototype.upHandler = function(oe) { + this.isDrag = false; + oe.popTool(); + + var rect = this.target.getBoundingClientRect(); + var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider']; + Neo.sliders[sliderType].upHandler(oe.rawMouseX - rect.left, + oe.rawMouseY - rect.top); +}; + +Neo.SliderTool.prototype.moveHandler = function(oe) { + if (this.isDrag) { + var rect = this.target.getBoundingClientRect(); + var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider']; + Neo.sliders[sliderType].moveHandler(oe.rawMouseX - rect.left, + oe.rawMouseY - rect.top); + } +}; + +Neo.SliderTool.prototype.upMoveHandler = function(oe) {} +Neo.SliderTool.prototype.rollOverHandler= function(oe) {} +Neo.SliderTool.prototype.rollOutHandler= function(oe) {} + +/* + ------------------------------------------------------------------------- + Fill(塗り潰し) + ------------------------------------------------------------------------- +*/ + +Neo.FillTool = function() {}; +Neo.FillTool.prototype = new Neo.ToolBase(); +Neo.FillTool.prototype.type = Neo.Painter.TOOLTYPE_FILL; +Neo.FillTool.prototype.isUpMove = false; + +Neo.FillTool.prototype.downHandler = function(oe) { + var x = Math.floor(oe.mouseX); + var y = Math.floor(oe.mouseY); + oe._pushUndo(); + oe.fill(x, y, oe.canvasCtx[oe.current]); +}; + +Neo.FillTool.prototype.upHandler = function(oe) { +}; + +Neo.FillTool.prototype.moveHandler = function(oe) { +}; + +Neo.FillTool.prototype.rollOutHandler= function(oe) {}; +Neo.FillTool.prototype.upMoveHandler = function(oe) {} +Neo.FillTool.prototype.rollOverHandler= function(oe) {} + + +/* + ------------------------------------------------------------------------- + EraseAll(全消し) + ------------------------------------------------------------------------- +*/ + +Neo.EraseAllTool = function() {}; +Neo.EraseAllTool.prototype = new Neo.ToolBase(); +Neo.EraseAllTool.prototype.type = Neo.Painter.TOOLTYPE_ERASEALL; +Neo.EraseAllTool.prototype.isUpMove = false; + +Neo.EraseAllTool.prototype.downHandler = function(oe) { + oe._pushUndo(); + + oe.prepareDrawing(); + oe.canvasCtx[oe.current].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +Neo.EraseAllTool.prototype.upHandler = function(oe) { +}; + +Neo.EraseAllTool.prototype.moveHandler = function(oe) { +}; + +Neo.EraseAllTool.prototype.rollOutHandler= function(oe) {}; +Neo.EraseAllTool.prototype.upMoveHandler = function(oe) {}; +Neo.EraseAllTool.prototype.rollOverHandler= function(oe) {}; + + +/* + ------------------------------------------------------------------------- + EffectToolBase(エフェックトツールのベースクラス) + ------------------------------------------------------------------------- +*/ + +Neo.EffectToolBase = function() {}; +Neo.EffectToolBase.prototype = new Neo.ToolBase(); +Neo.EffectToolBase.prototype.isUpMove = false; + +Neo.EffectToolBase.prototype.downHandler = function(oe) { + this.isUpMove = false; + + this.startX = this.endX = oe.clipMouseX; + this.startY = this.endY = oe.clipMouseY; +}; + +Neo.EffectToolBase.prototype.upHandler = function(oe) { + if (this.isUpMove) return; + this.isUpMove = true; + + this.startX = Math.floor(this.startX); + this.startY = Math.floor(this.startY); + this.endX = Math.floor(this.endX); + this.endY = Math.floor(this.endY); + + var x = (this.startX < this.endX) ? this.startX : this.endX; + var y = (this.startY < this.endY) ? this.startY : this.endY; + var width = Math.abs(this.startX - this.endX) + 1; + var height = Math.abs(this.startY - this.endY) + 1; + var ctx = oe.canvasCtx[oe.current]; + + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x + width > oe.canvasWidth) width = oe.canvasWidth - x; + if (y + height > oe.canvasHeight) height = oe.canvasHeight - y; + + if (width > 0 && height > 0) { + oe._pushUndo(); + oe.prepareDrawing(); + this.doEffect(oe, x, y, width, height); + } + + if (oe.tool.type != Neo.Painter.TOOLTYPE_PASTE) { + oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + } +}; + +Neo.EffectToolBase.prototype.moveHandler = function(oe) { + this.endX = oe.clipMouseX; + this.endY = oe.clipMouseY; + + oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true); + this.drawCursor(oe); +}; + +Neo.EffectToolBase.prototype.rollOutHandler= function(oe) {}; +Neo.EffectToolBase.prototype.upMoveHandler = function(oe) {}; +Neo.EffectToolBase.prototype.rollOverHandler= function(oe) {}; + +Neo.EffectToolBase.prototype.drawCursor = function(oe) { + var ctx = oe.destCanvasCtx; + + ctx.save(); + this.transformForZoom(oe); + + var start = oe.getDestCanvasPosition(this.startX, this.startY, true); + var end = oe.getDestCanvasPosition(this.endX, this.endY, true); + + var x = (start.x < end.x) ? start.x : end.x; + var y = (start.y < end.y) ? start.y : end.y; + var width = Math.abs(start.x - end.x) + oe.zoom; + var height = Math.abs(start.y - end.y) + oe.zoom; + + if (this.isEllipse) { + oe.drawXOREllipse(ctx, x, y, width, height, this.isFill); + + } else { + oe.drawXORRect(ctx, x, y, width, height, this.isFill); + } + ctx.restore(); +}; + +Neo.EffectToolBase.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = this.defaultAlpha || 1.0; + Neo.updateUI(); + }; +}; + +/* + ------------------------------------------------------------------------- + EraseRect(消し四角) + ------------------------------------------------------------------------- +*/ + +Neo.EraseRectTool = function() {}; +Neo.EraseRectTool.prototype = new Neo.EffectToolBase(); +Neo.EraseRectTool.prototype.type = Neo.Painter.TOOLTYPE_ERASERECT; + +Neo.EraseRectTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.eraseRect(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + FlipH(左右反転) + ------------------------------------------------------------------------- +*/ + +Neo.FlipHTool = function() {}; +Neo.FlipHTool.prototype = new Neo.EffectToolBase(); +Neo.FlipHTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_H; + +Neo.FlipHTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.flipH(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + FlipV(上下反転) + ------------------------------------------------------------------------- +*/ + +Neo.FlipVTool = function() {}; +Neo.FlipVTool.prototype = new Neo.EffectToolBase(); +Neo.FlipVTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_V; + +Neo.FlipVTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.flipV(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + DodgeRect(角取り) + ------------------------------------------------------------------------- +*/ + +Neo.BlurRectTool = function() {}; +Neo.BlurRectTool.prototype = new Neo.EffectToolBase(); +Neo.BlurRectTool.prototype.type = Neo.Painter.TOOLTYPE_BLURRECT; + +Neo.BlurRectTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.blurRect(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +Neo.BlurRectTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 0.5; + Neo.updateUI(); + }; +} + +/* + ------------------------------------------------------------------------- + Turn(傾け) + ------------------------------------------------------------------------- +*/ + +Neo.TurnTool = function() {}; +Neo.TurnTool.prototype = new Neo.EffectToolBase(); +Neo.TurnTool.prototype.type = Neo.Painter.TOOLTYPE_TURN; + +Neo.TurnTool.prototype.upHandler = function(oe) { + this.isUpMove = true; + + this.startX = Math.floor(this.startX); + this.startY = Math.floor(this.startY); + this.endX = Math.floor(this.endX); + this.endY = Math.floor(this.endY); + + var x = (this.startX < this.endX) ? this.startX : this.endX; + var y = (this.startY < this.endY) ? this.startY : this.endY; + var width = Math.abs(this.startX - this.endX) + 1; + var height = Math.abs(this.startY - this.endY) + 1; + + if (width > 0 && height > 0) { + oe._pushUndo(); + oe.turn(x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + } +}; + +/* + ------------------------------------------------------------------------- + Merge(レイヤー結合) + ------------------------------------------------------------------------- +*/ + +Neo.MergeTool = function() {}; +Neo.MergeTool.prototype = new Neo.EffectToolBase(); +Neo.MergeTool.prototype.type = Neo.Painter.TOOLTYPE_MERGE; + +Neo.MergeTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.merge(ctx, x, y, width, height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + Copy(コピー) + ------------------------------------------------------------------------- +*/ + +Neo.CopyTool = function() {}; +Neo.CopyTool.prototype = new Neo.EffectToolBase(); +Neo.CopyTool.prototype.type = Neo.Painter.TOOLTYPE_COPY; + +Neo.CopyTool.prototype.doEffect = function(oe, x, y, width, height) { + oe.copy(x, y, width, height); + oe.setToolByType(Neo.Painter.TOOLTYPE_PASTE); + oe.tool.x = x; + oe.tool.y = y; + oe.tool.width = width; + oe.tool.height = height; +}; + +/* + ------------------------------------------------------------------------- + Paste(ペースト) + ------------------------------------------------------------------------- +*/ + +Neo.PasteTool = function() {}; +Neo.PasteTool.prototype = new Neo.ToolBase(); +Neo.PasteTool.prototype.type = Neo.Painter.TOOLTYPE_PASTE; + +Neo.PasteTool.prototype.downHandler = function(oe) { + this.startX = oe.mouseX; + this.startY = oe.mouseY; + this.drawCursor(oe); +}; + +Neo.PasteTool.prototype.upHandler = function(oe) { + oe._pushUndo(); + + oe.paste(this.x, this.y, this.width, this.height); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + + oe.setToolByType(Neo.Painter.TOOLTYPE_COPY); +}; + +Neo.PasteTool.prototype.moveHandler = function(oe) { + var dx = Math.floor(oe.mouseX - this.startX); + var dy = Math.floor(oe.mouseY - this.startY); + oe.tempX = dx; + oe.tempY = dy; + + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + // this.drawCursor(oe); +}; + +Neo.PasteTool.prototype.keyDownHandler = function(e) { + if (e.keyCode == 27) { //Escでキャンセル + var oe = Neo.painter; + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + oe.setToolByType(Neo.Painter.TOOLTYPE_COPY); + } +}; + +Neo.PasteTool.prototype.drawCursor = function(oe) { + var ctx = oe.destCanvasCtx; + + ctx.save(); + this.transformForZoom(oe); + + var start = oe.getDestCanvasPosition(this.x, this.y, true); + var end = oe.getDestCanvasPosition(this.x + this.width, this.y + this.height, true); + + var x = start.x + oe.tempX * oe.zoom; + var y = start.y + oe.tempY * oe.zoom; + var width = Math.abs(start.x - end.x); + var height = Math.abs(start.y - end.y); + oe.drawXORRect(ctx, x, y, width, height); + ctx.restore(); +}; + +/* + ------------------------------------------------------------------------- + Rect(線四角) + ------------------------------------------------------------------------- +*/ + +Neo.RectTool = function() {}; +Neo.RectTool.prototype = new Neo.EffectToolBase(); +Neo.RectTool.prototype.type = Neo.Painter.TOOLTYPE_RECT; + +Neo.RectTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.rectMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + RectFill(四角) + ------------------------------------------------------------------------- +*/ + +Neo.RectFillTool = function() {}; +Neo.RectFillTool.prototype = new Neo.EffectToolBase(); +Neo.RectFillTool.prototype.type = Neo.Painter.TOOLTYPE_RECTFILL; + +Neo.RectFillTool.prototype.isFill = true; +Neo.RectFillTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.rectFillMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + Ellipse(線楕円) + ------------------------------------------------------------------------- +*/ + +Neo.EllipseTool = function() {}; +Neo.EllipseTool.prototype = new Neo.EffectToolBase(); +Neo.EllipseTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSE; +Neo.EllipseTool.prototype.isEllipse = true; +Neo.EllipseTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.ellipseMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + EllipseFill(楕円) + ------------------------------------------------------------------------- +*/ + +Neo.EllipseFillTool = function() {}; +Neo.EllipseFillTool.prototype = new Neo.EffectToolBase(); +Neo.EllipseFillTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSEFILL; +Neo.EllipseFillTool.prototype.isEllipse = true; +Neo.EllipseFillTool.prototype.isFill = true; +Neo.EllipseFillTool.prototype.doEffect = function(oe, x, y, width, height) { + var ctx = oe.canvasCtx[oe.current]; + oe.doFill(ctx, x, y, width, height, oe.ellipseFillMask); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); +}; + +/* + ------------------------------------------------------------------------- + Text(テキスト) + ------------------------------------------------------------------------- +*/ + +Neo.TextTool = function() {}; +Neo.TextTool.prototype = new Neo.ToolBase(); +Neo.TextTool.prototype.type = Neo.Painter.TOOLTYPE_TEXT; +Neo.TextTool.prototype.isUpMove = false; + +Neo.TextTool.prototype.downHandler = function(oe) { + this.startX = oe.mouseX; + this.startY = oe.mouseY; + + if (Neo.painter.inputText) { + Neo.painter.updateInputText(); + + var rect = oe.container.getBoundingClientRect(); + var text = Neo.painter.inputText; + var x = oe.rawMouseX - rect.left - 5; + var y = oe.rawMouseY - rect.top - 5; + + text.style.left = x + "px"; + text.style.top = y + "px"; + text.style.display = "block"; + text.focus(); + } +}; + +Neo.TextTool.prototype.upHandler = function(oe) { +}; + +Neo.TextTool.prototype.moveHandler = function(oe) {}; +Neo.TextTool.prototype.upMoveHandler = function(oe) {}; +Neo.TextTool.prototype.rollOverHandler= function(oe) {}; +Neo.TextTool.prototype.rollOutHandler= function(oe) {}; + +Neo.TextTool.prototype.keyDownHandler = function(e) { + if (e.keyCode == 13) { // Returnで確定 + e.preventDefault(); + + var oe = Neo.painter; + var text = oe.inputText; + if (text) { + oe._pushUndo(); + this.drawText(oe); + oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true); + + text.style.display = "none"; + text.blur(); + } + } +}; + +Neo.TextTool.prototype.kill = function(oe) { + Neo.painter.hideInputText(); +}; + +Neo.TextTool.prototype.drawText = function(oe) { + var text = oe.inputText; + + // unescape entities + //var tmp = document.createElement("textarea"); + //tmp.innerHTML = text.innerHTML; + //var string = tmp.value; + + var string = text.textContent || text.innerText; + + if (string.length <= 0) return; + oe.doText(this.startX, this.startY, string, text.style.fontSize); +}; + +Neo.TextTool.prototype.loadStates = function() { + var reserve = this.getReserve(); + if (reserve) { + Neo.painter.lineWidth = reserve.size; + Neo.painter.alpha = 1.0; + Neo.updateUI(); + }; +}; + +/* + ------------------------------------------------------------------------- + Dummy(何もしない時) + ------------------------------------------------------------------------- +*/ + +Neo.DummyTool = function() {}; +Neo.DummyTool.prototype = new Neo.ToolBase(); +Neo.DummyTool.prototype.type = Neo.Painter.TOOLTYPE_NONE; +Neo.DummyTool.prototype.isUpMove = false; + +Neo.DummyTool.prototype.downHandler = function(oe) { +}; + +Neo.DummyTool.prototype.upHandler = function(oe) { + oe.popTool(); +}; + +Neo.DummyTool.prototype.moveHandler = function(oe) {}; +Neo.DummyTool.prototype.upMoveHandler = function(oe) {} +Neo.DummyTool.prototype.rollOverHandler= function(oe) {} +Neo.DummyTool.prototype.rollOutHandler= function(oe) {} + +'use strict'; + +Neo.CommandBase = function() { +}; +Neo.CommandBase.prototype.data; +Neo.CommandBase.prototype.execute = function() {} + + +/* + --------------------------------------------------- + ZOOM + --------------------------------------------------- +*/ +Neo.ZoomPlusCommand = function(data) {this.data = data}; +Neo.ZoomPlusCommand.prototype = new Neo.CommandBase(); +Neo.ZoomPlusCommand.prototype.execute = function() { + if (this.data.zoom < 12) { + this.data.setZoom(this.data.zoom + 1); + } + Neo.resizeCanvas(); + Neo.painter.updateDestCanvas(); +}; + +Neo.ZoomMinusCommand = function(data) {this.data = data}; +Neo.ZoomMinusCommand.prototype = new Neo.CommandBase(); +Neo.ZoomMinusCommand.prototype.execute = function() { + if (this.data.zoom >= 2) { + this.data.setZoom(this.data.zoom - 1); + } + Neo.resizeCanvas(); + Neo.painter.updateDestCanvas(); +}; + +/* + --------------------------------------------------- + UNDO + --------------------------------------------------- +*/ +Neo.UndoCommand = function(data) {this.data = data}; +Neo.UndoCommand.prototype = new Neo.CommandBase(); +Neo.UndoCommand.prototype.execute = function() { + this.data.undo(); +}; + +Neo.RedoCommand = function(data) {this.data = data}; +Neo.RedoCommand.prototype = new Neo.CommandBase(); +Neo.RedoCommand.prototype.execute = function() { + this.data.redo(); +}; + + +Neo.WindowCommand = function(data) {this.data = data}; +Neo.WindowCommand.prototype = new Neo.CommandBase(); +Neo.WindowCommand.prototype.execute = function() { + if (Neo.fullScreen) { + if (confirm(Neo.translate("ページビュー?"))) { + Neo.fullScreen = false; + Neo.updateWindow(); + } + } else { + if (confirm(Neo.translate("ウィンドウビュー?"))) { + Neo.fullScreen = true; + Neo.updateWindow(); + } + } +}; + +Neo.SubmitCommand = function(data) {this.data = data}; +Neo.SubmitCommand.prototype = new Neo.CommandBase(); +Neo.SubmitCommand.prototype.execute = function() { + var board = location.href.replace(/[^/]*$/, ''); + console.log("submit: " + board); + this.data.submit(board); +}; + +Neo.CopyrightCommand = function(data) {this.data = data}; +Neo.CopyrightCommand.prototype = new Neo.CommandBase(); +Neo.CopyrightCommand.prototype.execute = function() { + var url = "http://github.com/funige/neo/"; + if (confirm(Neo.translate("PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?") + "\n")) { + Neo.openURL(url); + } +}; + +'use strict'; + +Neo.getModifier = function(e) { + if (e.shiftKey) { + return 'shift'; + + } else if (e.button == 2 || e.ctrlKey || e.altKey || Neo.painter.virtualRight) { + return 'right'; + } + return null; +} + +/* + ------------------------------------------------------------------------- + Button + ------------------------------------------------------------------------- +*/ + +Neo.Button = function() {}; +Neo.Button.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.selected = false; + this.isMouseDown = false; + + var ref = this; + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.onmouseup = function(e) { ref._mouseUpHandler(e); } + this.element.onmouseover = function(e) { ref._mouseOverHandler(e); } + this.element.onmouseout = function(e) { ref._mouseOutHandler(e); } + this.element.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + e.preventDefault(); + }, true); + this.element.addEventListener("touchend", function(e) { + ref._mouseUpHandler(e); + }, true); + + + this.element.className = (!this.params.type == "fill") ? "button" : "buttonOff"; + + return this; +}; + +Neo.Button.prototype._mouseDownHandler = function(e) { + if (Neo.painter.isUIPaused()) return; + this.isMouseDown = true; + + if ((this.params.type == "fill") && (this.selected == false)) { + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + toolTip.setSelected((this.selected) ? false : true); + } + Neo.painter.setToolByType(Neo.Painter.TOOLTYPE_FILL); + } + + if (this.onmousedown) this.onmousedown(this); +}; +Neo.Button.prototype._mouseUpHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + + if (this.onmouseup) this.onmouseup(this); + } +}; +Neo.Button.prototype._mouseOutHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseout) this.onmouseout(this); + } +}; +Neo.Button.prototype._mouseOverHandler = function(e) { + if (this.onmouseover) this.onmouseover(this); +}; + +Neo.Button.prototype.setSelected = function(selected) { + if (selected) { + this.element.className = "buttonOn"; + } else { + this.element.className = "buttonOff"; + } + this.selected = selected; +}; + +Neo.Button.prototype.update = function() { +}; + +/* + ------------------------------------------------------------------------- + Right Button + ------------------------------------------------------------------------- +*/ + +Neo.RightButton; + +Neo.RightButton = function() {}; +Neo.RightButton.prototype = new Neo.Button(); + +Neo.RightButton.prototype.init = function(name, params) { + Neo.Button.prototype.init.call(this, name, params); + this.params.type = "right"; + return this; +} + +Neo.RightButton.prototype._mouseDownHandler = function(e) { +}; + +Neo.RightButton.prototype._mouseUpHandler = function(e) { + this.setSelected(!this.selected) +}; + +Neo.RightButton.prototype._mouseOutHandler = function(e) { +}; + +Neo.RightButton.prototype.setSelected = function (selected) { + if (selected) { + this.element.className = "buttonOn"; + Neo.painter.virtualRight = true; + } else { + this.element.className = "buttonOff"; + Neo.painter.virtualRight = false; + } + this.selected = selected; +}; + +Neo.RightButton.clear = function () { + var right = Neo.rightButton; + right.setSelected(false); +}; + +/* + ------------------------------------------------------------------------- + Fill Button + ------------------------------------------------------------------------- +*/ + +Neo.FillButton; + +Neo.FillButton = function() {}; +Neo.FillButton.prototype = new Neo.Button(); + +Neo.FillButton.prototype.init = function(name, params) { + Neo.Button.prototype.init.call(this, name, params); + this.params.type = "fill"; + return this; +} + +/* + ------------------------------------------------------------------------- + ColorTip + ------------------------------------------------------------------------- +*/ + +Neo.colorTips = []; + +Neo.ColorTip = function() {}; +Neo.ColorTip.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + + this.selected = (this.name == "color1") ? true : false; + this.isMouseDown = false; + + var ref = this; + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.onmouseup = function(e) { ref._mouseUpHandler(e); } + this.element.onmouseover = function(e) { ref._mouseOverHandler(e); } + this.element.onmouseout = function(e) { ref._mouseOutHandler(e); } + this.element.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + e.preventDefault(); + }, true); + this.element.addEventListener("touchend", function(e) { + ref._mouseUpHandler(e); + }, true); + + this.element.className = "colorTipOff"; + + var index = parseInt(this.name.slice(5)) - 1; + this.element.style.left = (index % 2) ? "0px" : "26px"; + this.element.style.top = Math.floor(index / 2) * 21 + "px"; + + // base64 ColorTip.png + this.element.innerHTML = "<img style='max-width:44px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAASCAYAAAAg9DzcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANklEQVRIx+3OAQkAMADDsO3+Pe8qCj+0Akq6bQFqS2wTCpwE+R4IiyVYsGDBggULfirBgn8HX7BzCRwDx1QeAAAAAElFTkSuQmCC' />" + + this.setColor(Neo.config.colors[params.index - 1]); + + this.setSelected(this.selected); + Neo.colorTips.push(this); +}; + +Neo.ColorTip.prototype._mouseDownHandler = function(e) { + if (Neo.painter.isUIPaused()) return; + this.isMouseDown = true; + + for (var i = 0; i < Neo.colorTips.length; i++) { + var colorTip = Neo.colorTips[i]; + if (this == colorTip) { + switch (Neo.getModifier(e)) { + case 'shift': + this.setColor(Neo.config.colors[this.params.index - 1]); + break; + case 'right': + this.setColor(Neo.painter.foregroundColor); + break; + } + +// if (e.shiftKey) { +// this.setColor(Neo.config.colors[this.params.index - 1]); +// } else if (e.button == 2 || e.ctrlKey || e.altKey || +// Neo.painter.virtualRight) { +// this.setColor(Neo.painter.foregroundColor); +// } + } + colorTip.setSelected(this == colorTip) ? true : false; + } + Neo.painter.setColor(this.color); + Neo.updateUIColor(true, false); + + if (this.onmousedown) this.onmousedown(this); +}; +Neo.ColorTip.prototype._mouseUpHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseup) this.onmouseup(this); + } +}; +Neo.ColorTip.prototype._mouseOutHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseout) this.onmouseout(this); + } +}; +Neo.ColorTip.prototype._mouseOverHandler = function(e) { + if (this.onmouseover) this.onmouseover(this); +}; + +Neo.ColorTip.prototype.setSelected = function(selected) { + if (selected) { + this.element.className = "colorTipOn"; + } else { + this.element.className = "colorTipOff"; + } + this.selected = selected; +}; + +Neo.ColorTip.prototype.setColor = function(color) { + this.color = color; + this.element.style.backgroundColor = color; +}; + +Neo.ColorTip.getCurrent = function() { + for (var i = 0; i < Neo.colorTips.length; i++) { + var colorTip = Neo.colorTips[i]; + if (colorTip.selected) return colorTip; + } + return null; +}; + +/* + ------------------------------------------------------------------------- + ToolTip + ------------------------------------------------------------------------- +*/ + +Neo.toolTips = []; +Neo.toolButtons = []; + +Neo.ToolTip = function() {}; + +Neo.ToolTip.prototype.prevMode = -1; + +Neo.ToolTip.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.params.type = this.element.id; + this.name = name; + this.mode = 0; + + this.isMouseDown = false; + + var ref = this; + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.onmouseup = function(e) { ref._mouseUpHandler(e); } + this.element.onmouseover = function(e) { ref._mouseOverHandler(e); } + this.element.onmouseout = function(e) { ref._mouseOutHandler(e); } + this.element.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + e.preventDefault(); + }, true); + this.element.addEventListener("touchend", function(e) { + ref._mouseUpHandler(e); + }, true); + + this.selected = (this.params.type == "pen") ? true : false; + this.setSelected(this.selected); + + this.element.innerHTML = "<canvas width=46 height=18></canvas><div class='label'></div>"; + this.canvas = this.element.getElementsByTagName('canvas')[0]; + this.label = this.element.getElementsByTagName('div')[0]; + + this.update(); + return this; +}; + +Neo.ToolTip.prototype._mouseDownHandler = function(e) { + this.isMouseDown = true; + + if (this.isTool) { + if (this.selected == false) { + for (var i = 0; i < Neo.toolButtons.length; i++) { + var toolTip = Neo.toolButtons[i]; + toolTip.setSelected((this == toolTip) ? true : false); + } + + } else { + var length = this.toolStrings.length; + if (Neo.getModifier(e) == "right") { + this.mode--; + if (this.mode < 0) this.mode = length - 1; + + } else { + this.mode++; + if (this.mode >= length) this.mode = 0; + } + } + Neo.painter.setToolByType(this.tools[this.mode]); + this.update(); + } + + if (this.onmousedown) this.onmousedown(this); +}; + +Neo.ToolTip.prototype._mouseUpHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseup) this.onmouseup(this); + } +}; + +Neo.ToolTip.prototype._mouseOutHandler = function(e) { + if (this.isMouseDown) { + this.isMouseDown = false; + if (this.onmouseout) this.onmouseout(this); + } +}; +Neo.ToolTip.prototype._mouseOverHandler = function(e) { + if (this.onmouseover) this.onmouseover(this); +}; + +Neo.ToolTip.prototype.setSelected = function(selected) { + if (this.fixed) { + this.element.className = "toolTipFixed"; + + } else { + if (selected) { + this.element.className = "toolTipOn"; + } else { + this.element.className = "toolTipOff"; + } + } + this.selected = selected; +}; + +Neo.ToolTip.prototype.update = function() {}; + +Neo.ToolTip.prototype.draw = function(c) { + if (this.hasTintImage) { + if (typeof c != "string") c = Neo.painter.getColorString(c); + var ctx = this.canvas.getContext("2d"); + + if (this.prevMode != this.mode) { + this.prevMode = this.mode; + + var img = new Image(); + img.src = this.toolIcons[this.mode]; + img.onload = function() { + var ref = this; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.drawTintImage(ctx, img, c, 0, 0); + }.bind(this); + + } else { + this.tintImage(ctx, c); + } + } +}; + +Neo.ToolTip.prototype.drawTintImage = function(ctx, img, c, x, y) { + ctx.drawImage(img, x, y); + this.tintImage(ctx, c); +}; + +Neo.ToolTip.prototype.tintImage = function(ctx, c) { + c = (Neo.painter.getColor(c) & 0xffffff); + + var imageData = ctx.getImageData(0, 0, 46, 18); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + + for (var i = 0; i < buf32.length; i++) { + var a = buf32[i] & 0xff000000; + if (a) { + buf32[i] = buf32[i] & a | c; + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); +}; + +Neo.ToolTip.bezier = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAT0lEQVRIx+3SQQoAIAhE0en+h7ZVEEKBZrX5b5sjKknAkRYpNslaMLPq44ZI9wwHs0vMQ/v87u0Kk8xfsaI242jbMdjPi5Y0r/zTAAAAD3UOjRf9jcO4sgAAAABJRU5ErkJggg=="; +Neo.ToolTip.blur = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAASUlEQVRIx+3VMQ4AIAgEQeD/f8bWWBnJYUh2SgtgK82G8/MhzVKwxOtTLgIUx6tDout4laiPIICA0Qj4bXxAy0+8LZP9yACAJwsqkggS55eiZgAAAABJRU5ErkJggg=="; +Neo.ToolTip.blurrect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAX0lEQVRIx+2XQQ4AEAwEt+I7/v+8Org6lJKt6NzLjjYE8DAKtLpYoDeCCCC7tYUd3ru2qQOzDTyndhJzB6KSAmxSgM0fAlGuzBnmlziqxB8jFJkUYJMCbAQYPxt2kF06fvYKgjPBO/IAAAAASUVORK5CYII="; +Neo.ToolTip.brush = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQUlEQVRIx2NgGOKAEcb4z8CweRA4xpdUPSxofJ8BdP8WcjQxDaCDqQLQY4CsUBgFo2AUjIJRMApGwSgYBaNgZAIA0CoDwDbZu8oAAAAASUVORK5CYII="; +Neo.ToolTip.burn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAPklEQVRIx+3PMRIAMAQAQbzM0/0sKZPeiDG57TQ4keH0Htx9VR+MCM1vOezl8xUsv4IAAkYjoBsB3QgAgL9tYXgF19rh9yoAAAAASUVORK5CYII="; +Neo.ToolTip.copy = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XMQoAIAwDU/E7/v95Orh2KMUSC7m5Qs6AUqAxG1gzOLirwxhgmXOjOlg1oQY8sjf2mvYNSICNBNhIgE3oH/jlzfdo34AE2EiATXsBA+5mww6S5QASDwSGMt8ouwAAAABJRU5ErkJggg=="; +Neo.ToolTip.copy2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAN0lEQVRIx+3PwQkAIBADwdPKt3MtQVCOPNz5B7JV0pNxOwRW9zng+G92n+hmQJoBaQakGSBJf9tyBgQUV/fKCAAAAABJRU5ErkJggg=="; +Neo.ToolTip.ellipse = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAATklEQVRIx+2VMQ4AIAgD6/8fjbOJi1LFmt4OPQ0KIE7LNgggCBLbHkuFM9lM+Om+QwDjpksyb4tT86vlvzgEbYxefQPyv5D8HjDGGGOk6b3jJ+lYubd8AAAAAElFTkSuQmCC"; +Neo.ToolTip.ellipsefill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAVUlEQVRIx+2VURIAEAgFc/9D5waSHpV5+43ZHRMizRnRA1REARLHHq6NCFl01Nail+LeEDMgU34nYhlQQd6K+PsGKkSEZyArBPoK3Y6K/AOEEEJIayZHbhIKjkZrFwAAAABJRU5ErkJggg=="; +Neo.ToolTip.eraser = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAABQElEQVRIx+1WQY7CMAwcI37Cad+yXOgH4Gu8gAt9CtrDirfMHjZJbbcktVSpQnROSeMkY3vsFHhzSG3xfLpz/JVmG0mIqDkIMcc6+7Kejx6fdb0dq7w09rVFkrjejrMOunQ9vg7f/5QEIAd6E1Eo38WF8fF7n8sdALCrLerIzoFI4sI0Vtv1SYZ8CVbeF7tzF7JugIkVkxOauc6CIe8842S+XmMfsq7TN9LRTngZmTmVD4SrnzYaGYhFoxCWgajXuMjYGTuJ3dlwIBIN3U0cUVqLXCs5E7YeVsvAYJul5HWeLUhL3EpstQwooqoOTEHDOebpMn7ngkUsg3RotU8X1MkuVDrYohkIupC0YArX6T+PfX3kcbQLNV/iCKi6EB3xqXdAZ0JKthZ8B0QEl673NIEX/0I/z36Rf6ENGzZ8EP4A8Lp+9e9VWC4AAAAASUVORK5CYII="; +Neo.ToolTip.flip = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAZklEQVRIx+2XQQoAIAgE1+g7/f95degWHSyTTXDOhTsSiUBgOtCq8mD3DiOA3NxTCVgKaLA0qHiFOsHSnC8ELKQAmxRgE15APQfWv9pzLjwX+CXsjvBPKAXYpACb8AICzM2GHeSWAfVOCIiJuQ9tAAAAAElFTkSuQmCC"; +Neo.ToolTip.freehand = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAdUlEQVRIx+2WUQrAMAhD3dj9r+y+VoSyLhYDynzQv1qiJlCR4hzeAhVRsiC3Jkj0c5hN7Lx7IQ9SphLE1ICdwko420purEWQuywN3pqxgcw2+WwAtU1GzoqiLZNwZBvMAIcO8y3YKUO8mkbmjPzjK9E0TUPjBoeyLAS0usjLAAAAAElFTkSuQmCC"; +Neo.ToolTip.line = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAU0lEQVRIx+2UQQ4AIAjD8P+PxivRGDQC47C+oN1hIgTLQAt4qIga2c23XYAVPkm3CVhlb4ShAa/rQgMi1i0NyFg3LaBq3bAA1LpfAd7/EkIIIR2YXFYSCpWS8w8AAAAASUVORK5CYII="; +Neo.ToolTip.merge = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XQQrAQAgDx9Lv9JF9+e6h54IINlgyZ4UMOYgwmAXXmRxc3WECorJ3dAfrJtXAC7c6PPygAQuosYAaC6hJ3YHqlfyC8Q1YQI0F1IwXCHg+G3WQKhvwgwUFmFyYbwAAAABJRU5ErkJggg=="; +Neo.ToolTip.pen = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAK0lEQVRIx+3OsQkAMAwDQXn/oe3WfSAEctd9I5TA32pHJ/3AoTpfAQCAGwaa5AICJLKWSQAAAABJRU5ErkJggg=="; +Neo.ToolTip.rect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQElEQVRIx+3TMQ4AIAhD0WK8/5VxdcIYY8rw3wok7YAEr6iGKaU74BY0ro+6FKhyDHe4VxRwm6eFLn8AAADwwQIwTQgGo9ZMywAAAABJRU5ErkJggg=="; +Neo.ToolTip.rectfill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANElEQVRIx+3PIQ4AIBADwcL//3xYBMEgLiQztmab0GvcxkqqO3ALPbbO7rBXDnRzAADgYwvqDwIMJlGb5QAAAABJRU5ErkJggg=="; +Neo.ToolTip.text = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAcUlEQVRIx+2VwQ7AIAhDy7L//2V2WmIYg+ky2KEv8aCCqYQqQMgrJNpUQMXEKKDmAPHyspgSrBBvLZu3cQqZEdwhfusq0KdkVR5HlFfBvpI0mtIzeusFot7vFPqYuzZYMXUFlzc+qrIn7tf/ACGEkIwDlEQ94YZjzcgAAAAASUVORK5CYII="; +Neo.ToolTip.tone = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAO0lEQVRIx+3PIQ4AMAgEwaP//zNVVZUELiQ7CgWstFy8IaVsPhT1Lb/T+fQEAtwIcCPAjQC39QEAgJIL6DQCFhAqsRkAAAAASUVORK5CYII="; + +/* + ------------------------------------------------------------------------- + PenTip + ------------------------------------------------------------------------- +*/ + +Neo.penTip; + +Neo.PenTip = function() {}; +Neo.PenTip.prototype = new Neo.ToolTip(); + +Neo.PenTip.prototype.tools = [Neo.Painter.TOOLTYPE_PEN, + Neo.Painter.TOOLTYPE_BRUSH, + Neo.Painter.TOOLTYPE_TEXT]; + +Neo.PenTip.prototype.hasTintImage = true; +Neo.PenTip.prototype.toolIcons = [Neo.ToolTip.pen, + Neo.ToolTip.brush, + Neo.ToolTip.text]; + +Neo.PenTip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("鉛筆"), + Neo.translate("水彩"), + Neo.translate("テキスト")]; + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.PenTip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + this.draw(Neo.painter.foregroundColor); + if (this.label) { + this.label.innerHTML = this.toolStrings[this.mode]; + } +}; + +/* + ------------------------------------------------------------------------- + Pen2Tip + ------------------------------------------------------------------------- +*/ + +Neo.pen2Tip; + +Neo.Pen2Tip = function() {}; +Neo.Pen2Tip.prototype = new Neo.ToolTip(); + +Neo.Pen2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_TONE, + Neo.Painter.TOOLTYPE_BLUR, + Neo.Painter.TOOLTYPE_DODGE, + Neo.Painter.TOOLTYPE_BURN]; + +Neo.Pen2Tip.prototype.hasTintImage = true; +Neo.Pen2Tip.prototype.toolIcons = [Neo.ToolTip.tone, + Neo.ToolTip.blur, + Neo.ToolTip.burn, + Neo.ToolTip.burn]; + +Neo.Pen2Tip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("トーン"), + Neo.translate("ぼかし"), + Neo.translate("覆い焼き"), + Neo.translate("焼き込み")]; + + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.Pen2Tip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + switch (this.tools[this.mode]) { + case Neo.Painter.TOOLTYPE_TONE: + this.drawTone(Neo.painter.foregroundColor); + break; + + case Neo.Painter.TOOLTYPE_DODGE: + this.draw(0xffc0c0c0); + break; + + case Neo.Painter.TOOLTYPE_BURN: + this.draw(0xff404040); + break; + + default: + this.draw(Neo.painter.foregroundColor); + break; + } + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +Neo.Pen2Tip.prototype.drawTone = function() { + var ctx = this.canvas.getContext("2d"); + + var imageData = ctx.getImageData(0, 0, 46, 18); + var buf32 = new Uint32Array(imageData.data.buffer); + var buf8 = new Uint8ClampedArray(imageData.data.buffer); + var c = Neo.painter.getColor() | 0xff000000; + var a = Math.floor(Neo.painter.alpha * 255); + var toneData = Neo.painter.getToneData(a); + + for (var j = 0; j < 18; j++) { + for (var i = 0; i < 46; i++) { + if (j >= 1 && j < 12 && + i >= 2 && i < 26 && + toneData[(i%4) + (j%4) * 4]) { + buf32[j * 46 + i] = c; + + } else { + buf32[j * 46 + i] = 0; + } + } + } + imageData.data.set(buf8); + ctx.putImageData(imageData, 0, 0); + + this.prevMode = this.mode; +}; + + +/* + ------------------------------------------------------------------------- + EraserTip + ------------------------------------------------------------------------- +*/ + +Neo.eraserTip; + +Neo.EraserTip = function() {}; +Neo.EraserTip.prototype = new Neo.ToolTip(); + +Neo.EraserTip.prototype.tools = [Neo.Painter.TOOLTYPE_ERASER, + Neo.Painter.TOOLTYPE_ERASERECT, + Neo.Painter.TOOLTYPE_ERASEALL]; + +Neo.EraserTip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("消しペン"), + Neo.translate("消し四角"), + Neo.translate("全消し")]; + + this.drawOnce = false; + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.EraserTip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + if (this.drawOnce == false) { + this.draw(); + this.drawOnce = true; + } + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +Neo.EraserTip.prototype.draw = function() { + var ctx = this.canvas.getContext("2d"); + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + var img = new Image(); + + img.src = Neo.ToolTip.eraser; + img.onload = function() { + ctx.drawImage(img, 0, 0); + }; +}; + +/* + ------------------------------------------------------------------------- + EffectTip + ------------------------------------------------------------------------- +*/ + +Neo.effectTip; + +Neo.EffectTip = function() {}; +Neo.EffectTip.prototype = new Neo.ToolTip(); + +Neo.EffectTip.prototype.tools = [Neo.Painter.TOOLTYPE_RECTFILL, + Neo.Painter.TOOLTYPE_RECT, + Neo.Painter.TOOLTYPE_ELLIPSEFILL, + Neo.Painter.TOOLTYPE_ELLIPSE]; + +Neo.EffectTip.prototype.hasTintImage = true; +Neo.EffectTip.prototype.toolIcons = [Neo.ToolTip.rectfill, + Neo.ToolTip.rect, + Neo.ToolTip.ellipsefill, + Neo.ToolTip.ellipse]; + +Neo.EffectTip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("四角"), + Neo.translate("線四角"), + Neo.translate("楕円"), + Neo.translate("線楕円")]; + + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.EffectTip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + this.draw(Neo.painter.foregroundColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +/* + ------------------------------------------------------------------------- + Effect2Tip + ------------------------------------------------------------------------- +*/ + +Neo.effect2Tip; + +Neo.Effect2Tip = function() {}; +Neo.Effect2Tip.prototype = new Neo.ToolTip(); + +Neo.Effect2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_COPY, + Neo.Painter.TOOLTYPE_MERGE, + Neo.Painter.TOOLTYPE_BLURRECT, + Neo.Painter.TOOLTYPE_FLIP_H, + Neo.Painter.TOOLTYPE_FLIP_V, + Neo.Painter.TOOLTYPE_TURN]; + +Neo.Effect2Tip.prototype.hasTintImage = true; +Neo.Effect2Tip.prototype.toolIcons = [Neo.ToolTip.copy, + Neo.ToolTip.merge, + Neo.ToolTip.blurrect, + Neo.ToolTip.flip, + Neo.ToolTip.flip, + Neo.ToolTip.flip]; + +Neo.Effect2Tip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("コピー"), + Neo.translate("レイヤ結合"), + Neo.translate("角取り"), + Neo.translate("左右反転"), + Neo.translate("上下反転"), + Neo.translate("傾け")]; + + this.isTool = true; + Neo.ToolTip.prototype.init.call(this, name, params); + + this.img = document.createElement("img"); + this.img.src = Neo.ToolTip.copy2; + this.element.appendChild(this.img); + return this; +}; + +Neo.Effect2Tip.prototype.update = function() { + for (var i = 0; i < this.tools.length; i++) { + if (Neo.painter.tool.type == this.tools[i]) this.mode = i; + } + + this.draw(Neo.painter.foregroundColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +/* + ------------------------------------------------------------------------- + MaskTip + ------------------------------------------------------------------------- +*/ + +Neo.maskTip; + +Neo.MaskTip = function() {}; +Neo.MaskTip.prototype = new Neo.ToolTip(); + +Neo.MaskTip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("通常"), + Neo.translate("マスク"), + Neo.translate("逆マスク"), + Neo.translate("加算"), + Neo.translate("逆加算")]; + + this.fixed = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.MaskTip.prototype._mouseDownHandler = function(e) { + this.isMouseDown = true; + + if (Neo.getModifier(e) == "right") { + Neo.painter.maskColor = Neo.painter.foregroundColor; + + } else { + var length = this.toolStrings.length; + this.mode++; + if (this.mode >= length) this.mode = 0; + Neo.painter.maskType = this.mode; + } + this.update(); + + if (this.onmousedown) this.onmousedown(this); +} + +Neo.MaskTip.prototype.update = function() { + this.draw(Neo.painter.maskColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +Neo.MaskTip.prototype.draw = function(c) { + if (typeof c != "string") c = Neo.painter.getColorString(c); + + var ctx = this.canvas.getContext("2d"); + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + ctx.fillStyle = c; + ctx.fillRect(1, 1, 43, 9); +}; + +/* + ------------------------------------------------------------------------- + DrawTip + ------------------------------------------------------------------------- +*/ + +Neo.drawTip; + +Neo.DrawTip = function() {}; +Neo.DrawTip.prototype = new Neo.ToolTip(); + +Neo.DrawTip.prototype.hasTintImage = true; +Neo.DrawTip.prototype.toolIcons = [Neo.ToolTip.freehand, + Neo.ToolTip.line, + Neo.ToolTip.bezier]; + +Neo.DrawTip.prototype.init = function(name, params) { + this.toolStrings = [Neo.translate("手書き"), + Neo.translate("直線"), + Neo.translate("BZ曲線")]; + + this.fixed = true; + Neo.ToolTip.prototype.init.call(this, name, params); + return this; +}; + +Neo.DrawTip.prototype._mouseDownHandler = function(e) { + this.isMouseDown = true; + + var length = this.toolStrings.length; + + if (Neo.getModifier(e) == "right") { + this.mode--; + if (this.mode < 0) this.mode = length - 1; + + } else { + this.mode++; + if (this.mode >= length) this.mode = 0; + } + Neo.painter.drawType = this.mode; + this.update(); + + if (this.onmousedown) this.onmousedown(this); +} + +Neo.DrawTip.prototype.update = function() { + this.mode = Neo.painter.drawType; + this.draw(Neo.painter.foregroundColor); + this.label.innerHTML = this.toolStrings[this.mode]; +}; + +/* + ------------------------------------------------------------------------- + ColorSlider + ------------------------------------------------------------------------- +*/ + +Neo.sliders = []; + +Neo.ColorSlider = function() {}; + +Neo.ColorSlider.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.isMouseDown = false; + this.value = 0; + this.type = this.params.type; + + this.element.className = "colorSlider"; + this.element.innerHTML = "<div class='slider'></div><div class='label'></div>"; + this.element.innerHTML += "<div class='hit'></div>"; + + this.slider = this.element.getElementsByClassName('slider')[0]; + this.label = this.element.getElementsByClassName('label')[0]; + this.hit = this.element.getElementsByClassName('hit')[0]; + this.hit['data-slider'] = params.type; + + switch (this.type) { + case Neo.SLIDERTYPE_RED: + this.prefix = "R"; + this.slider.style.backgroundColor = "#fa9696"; + break; + case Neo.SLIDERTYPE_GREEN: + this.prefix = "G"; + this.slider.style.backgroundColor = "#82f238"; + break; + case Neo.SLIDERTYPE_BLUE: + this.prefix = "B"; + this.slider.style.backgroundColor = "#8080ff"; + break; + case Neo.SLIDERTYPE_ALPHA: + this.prefix = "A"; + this.slider.style.backgroundColor = "#aaaaaa"; + this.value = 255; + break; + } + + this.update(); + return this; +}; + +Neo.ColorSlider.prototype.downHandler = function(x, y) { + if (Neo.painter.isShiftDown) { + this.shift(x, y); + + } else { + this.slide(x, y); + } +}; + +Neo.ColorSlider.prototype.moveHandler = function(x, y) { + this.slide(x, y); + //event.preventDefault(); +}; + +Neo.ColorSlider.prototype.upHandler = function(x, y) { +}; + +Neo.ColorSlider.prototype.shift = function(x, y) { + var value; + if (x >= 0 && x < 60 && y >= 0 && y <= 15) { + var v = Math.floor((x - 5) * 5.0); + var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0; + + value = Math.max(Math.min(v, 255), min); + if (this.value > value || this.value == 255) { + this.value--; + } else { + this.value++; + } + this.value = Math.max(Math.min(this.value, 255), min); + this.value0 = this.value; + this.x0 = x; + } + + if (this.type == Neo.SLIDERTYPE_ALPHA) { + Neo.painter.alpha = this.value / 255.0; + this.update(); + Neo.updateUIColor(false, false); + + } else { + var r = Neo.sliders[Neo.SLIDERTYPE_RED].value; + var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value; + var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value; + + Neo.painter.setColor(r<<16 | g<<8 | b); + Neo.updateUIColor(true, true); + } +}; + +Neo.ColorSlider.prototype.slide = function(x, y) { + var value; + if (x >= 0 && x < 60 && y >= 0 && y <= 15) { + var v = Math.floor((x - 5) * 5.0); + value = Math.round(v / 5) * 5; + + this.value0 = value; + this.x0 = x; + + } else { + var d = (x - this.x0) / 3.0; + value = this.value0 + d; + } + + var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0; + this.value = Math.max(Math.min(value, 255), min); + + if (this.type == Neo.SLIDERTYPE_ALPHA) { + Neo.painter.alpha = this.value / 255.0; + this.update(); + Neo.updateUIColor(false, false); + + } else { + var r = Neo.sliders[Neo.SLIDERTYPE_RED].value; + var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value; + var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value; + var color = (r<<16 | g<<8 | b); + + var colorTip = Neo.ColorTip.getCurrent() + if (colorTip) { + colorTip.setColor(Neo.painter.getColorString(color)) + } + + Neo.painter.setColor(color); + // Neo.updateUIColor(true, true); + } +}; + +Neo.ColorSlider.prototype.update = function() { + var color = Neo.painter.getColor(); + var alpha = Neo.painter.alpha * 255; + + switch (this.type) { + case Neo.SLIDERTYPE_RED: this.value = (color & 0x0000ff); break; + case Neo.SLIDERTYPE_GREEN: this.value = (color & 0x00ff00) >> 8; break; + case Neo.SLIDERTYPE_BLUE: this.value = (color & 0xff0000) >> 16; break; + case Neo.SLIDERTYPE_ALPHA: this.value = alpha; break; + } + + var width = this.value * 49.0 / 255.0; + width = Math.max(Math.min(48, width), 1); + + this.slider.style.width = width.toFixed(2) + "px"; + this.label.innerHTML = this.prefix + this.value.toFixed(0); +}; + +/* + ------------------------------------------------------------------------- + SizeSlider + ------------------------------------------------------------------------- +*/ + +Neo.SizeSlider = function() {}; + +Neo.SizeSlider.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.isMouseDown = false; + this.value = this.value0 = 1; + + this.element.className = "sizeSlider"; + this.element.innerHTML = "<div class='slider'></div><div class='label'></div>"; + this.element.innerHTML += "<div class='hit'></div>" + + this.slider = this.element.getElementsByClassName('slider')[0]; + this.label = this.element.getElementsByClassName('label')[0]; + this.hit = this.element.getElementsByClassName('hit')[0]; + this.hit['data-slider'] = params.type; + + this.slider.style.backgroundColor = Neo.painter.foregroundColor; + this.update(); + return this; +}; + +Neo.SizeSlider.prototype.downHandler = function(x, y) { + if (Neo.painter.isShiftDown) { + this.shift(x, y); + + } else { + this.value0 = this.value; + this.y0 = y; + this.slide(x, y); + } +}; + +Neo.SizeSlider.prototype.moveHandler = function(x, y) { + this.slide(x, y); + //event.preventDefault(); +}; + +Neo.SizeSlider.prototype.upHandler = function(x, y) { +}; + +Neo.SizeSlider.prototype.shift = function(x, y) { + var value0 = Neo.painter.lineWidth; + var value; + + if (!Neo.painter.tool.alt) { + var v = Math.floor((y - 4) * 30.0 / 33.0); + + value = Math.max(Math.min(v, 30), 1); + if (value0 > value || value0 == 30) { + value0--; + } else { + value0++; + } + this.setSize(value0); + } +}; + +Neo.SizeSlider.prototype.slide = function(x, y) { + var value; + if (!Neo.painter.tool.alt) { + if (x >= 0 && x < 48 && y >= 0 && y < 41) { + var v = Math.floor((y - 4) * 30.0 / 33.0); + value = v; + + this.value0 = value; + this.y0 = y; + + } else { + var d = (y - this.y0) / 7.0; + value = this.value0 + d; + } + } else { + // Ctrl+Alt+ドラッグでサイズ変更するとき + var d = y - this.y0; + value = this.value0 + d; + } + + value = Math.max(Math.min(value, 30), 1); + this.setSize(value); +}; + +Neo.SizeSlider.prototype.setSize = function(value) { + value = Math.round(value); + Neo.painter.lineWidth = Math.max(Math.min(30, value), 1); + + var tool = Neo.painter.getCurrentTool(); + if (tool) { + if (tool.type == Neo.Painter.TOOLTYPE_BRUSH) { + Neo.painter.alpha = tool.getAlpha(); + Neo.sliders[Neo.SLIDERTYPE_ALPHA].update(); + + } else if (tool.type == Neo.Painter.TOOLTYPE_TEXT) { + Neo.painter.updateInputText(); + } + } + this.update(); +}; + +Neo.SizeSlider.prototype.update = function() { + this.value = Neo.painter.lineWidth; + + var height = this.value * 33.0 / 30.0; + height = Math.max(Math.min(34, height), 1); + + this.slider.style.height = height.toFixed(2) + "px"; + this.label.innerHTML = this.value + "px"; + this.slider.style.backgroundColor = Neo.painter.foregroundColor; +}; + +/* + ------------------------------------------------------------------------- + LayerControl + ------------------------------------------------------------------------- +*/ + +Neo.LayerControl = function() {}; +Neo.LayerControl.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + this.isMouseDown = false; + + var ref = this; + + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + e.preventDefault(); + }, true); + + this.element.className = "layerControl"; + + var layerStrings = [Neo.translate("Layer0"), + Neo.translate("Layer1")]; + + this.element.innerHTML = + "<div class='bg'></div><div class='label0'>" + layerStrings[0] + + "</div><div class='label1'>" + layerStrings[1] + + "</div><div class='line1'></div><div class='line0'></div>"; + + this.bg = this.element.getElementsByClassName('bg')[0]; + this.label0 = this.element.getElementsByClassName('label0')[0]; + this.label1 = this.element.getElementsByClassName('label1')[0]; + this.line0 = this.element.getElementsByClassName('line0')[0]; + this.line1 = this.element.getElementsByClassName('line1')[0]; + + this.line0.style.display = "none"; + this.line1.style.display = "none"; + this.label1.style.display = "none"; + + this.update(); + return this; +}; + +Neo.LayerControl.prototype._mouseDownHandler = function(e) { + if (Neo.getModifier(e) == "right") { + var visible = Neo.painter.visible[Neo.painter.current]; + Neo.painter.visible[Neo.painter.current] = (visible) ? false : true; + + } else { + var current = Neo.painter.current; + Neo.painter.current = (current) ? 0 : 1 + } + Neo.painter.updateDestCanvas(0, 0, Neo.painter.canvasWidth, Neo.painter.canvasHeight); + if (Neo.painter.tool.type == Neo.Painter.TOOLTYPE_PASTE) { + Neo.painter.tool.drawCursor(Neo.painter); + } + this.update(); + + if (this.onmousedown) this.onmousedown(this); +}; + +Neo.LayerControl.prototype.update = function() { + this.label0.style.display = (Neo.painter.current == 0) ? "block" : "none"; + this.label1.style.display = (Neo.painter.current == 1) ? "block" : "none"; + this.line0.style.display = (Neo.painter.visible[0]) ? "none" : "block"; + this.line1.style.display = (Neo.painter.visible[1]) ? "none" : "block"; +}; + +/* + ------------------------------------------------------------------------- + ReserveControl + ------------------------------------------------------------------------- +*/ +Neo.reserveControls = []; + +Neo.ReserveControl = function() {}; +Neo.ReserveControl.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + + var ref = this; + + this.element.onmousedown = function(e) { ref._mouseDownHandler(e); } + this.element.addEventListener("touchstart", function(e) { + ref._mouseDownHandler(e); + e.preventDefault(); + }, true); + + this.element.className = "reserve"; + + var index = parseInt(this.name.slice(7)) - 1; + this.element.style.top = "1px"; + this.element.style.left = (index * 15 + 2) + "px"; + + this.reserve = Neo.clone(Neo.config.reserves[index]); + this.update(); + + Neo.reserveControls.push(this); + return this; +}; + +Neo.ReserveControl.prototype._mouseDownHandler = function(e) { + if (Neo.getModifier(e) == 'right') { + this.save(); + } else { + this.load(); + } + this.update(); +}; + +Neo.ReserveControl.prototype.load = function() { + Neo.painter.setToolByType(this.reserve.tool) + Neo.painter.foregroundColor = this.reserve.color; + Neo.painter.lineWidth = this.reserve.size; + Neo.painter.alpha = this.reserve.alpha; + + switch (this.reserve.tool) { + case Neo.Painter.TOOLTYPE_PEN: + case Neo.Painter.TOOLTYPE_BRUSH: + case Neo.Painter.TOOLTYPE_TONE: + Neo.painter.drawType = this.reserve.drawType; + }; + Neo.updateUI(); +}; + +Neo.ReserveControl.prototype.save = function() { + this.reserve.color = Neo.painter.foregroundColor; + this.reserve.size = Neo.painter.lineWidth; + this.reserve.drawType = Neo.painter.drawType; + this.reserve.alpha = Neo.painter.alpha; + this.reserve.tool = Neo.painter.tool.getType(); + this.element.style.backgroundColor = this.reserve.color; + this.update(); + Neo.updateUI(); +}; + +Neo.ReserveControl.prototype.update = function() { + this.element.style.backgroundColor = this.reserve.color; +}; + +/* + ------------------------------------------------------------------------- + ScrollBarButton + ------------------------------------------------------------------------- +*/ + +Neo.scrollH; +Neo.scrollV; + +Neo.ScrollBarButton = function() {}; +Neo.ScrollBarButton.prototype.init = function(name, params) { + this.element = document.getElementById(name); + this.params = params || {}; + this.name = name; + + this.element.innerHTML = "<div></div>"; + this.barButton = this.element.getElementsByTagName("div")[0]; + this.element['data-bar'] = true; + this.barButton['data-bar'] = true; + + if (name == "scrollH") Neo.scrollH = this; + if (name == "scrollV") Neo.scrollV = this; + return this; +}; + +Neo.ScrollBarButton.prototype.update = function(oe) { + if (this.name == "scrollH") { + var a = oe.destCanvas.width / (oe.canvasWidth * oe.zoom); + var barWidth = Math.ceil(oe.destCanvas.width * a); + var barX = (oe.scrollBarX) * (oe.destCanvas.width - barWidth); + this.barButton.style.width = (Math.ceil(barWidth) - 4) + "px"; + this.barButton.style.left = Math.floor(barX) + "px"; + + } else { + var a = oe.destCanvas.height / (oe.canvasHeight * oe.zoom); + var barHeight = Math.ceil(oe.destCanvas.height * a); + var barY = (oe.scrollBarY) * (oe.destCanvas.height - barHeight); + this.barButton.style.height = (Math.ceil(barHeight) - 4) + "px"; + this.barButton.style.top = Math.floor(barY) + "px"; + } +}; + |