ultimatepp/uppsrc/Turtle/Turtle.html
oblivion 7c872a7d97 Turtle: MouseIn() method implemented. (using onmouseover event)
git-svn-id: svn://ultimatepp.org/upp/trunk@15013 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2020-09-10 20:38:54 +00:00

587 lines
19 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
html, body {
width: 100%;
height: 100%;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="1000" height="1000" style="border:0px" tabindex="1" oncontextmenu="return false;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
// zlib.js for inflate
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';function m(b){throw b;}var n=void 0,r=this;function s(b,d){var a=b.split("."),c=r;!(a[0]in c)&&c.execScript&&c.execScript("var "+a[0]);for(var f;a.length&&(f=a.shift());)!a.length&&d!==n?c[f]=d:c=c[f]?c[f]:c[f]={}};var u="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array;function v(b){var d=b.length,a=0,c=Number.POSITIVE_INFINITY,f,e,g,h,k,l,q,p,t;for(p=0;p<d;++p)b[p]>a&&(a=b[p]),b[p]<c&&(c=b[p]);f=1<<a;e=new (u?Uint32Array:Array)(f);g=1;h=0;for(k=2;g<=a;){for(p=0;p<d;++p)if(b[p]===g){l=0;q=h;for(t=0;t<g;++t)l=l<<1|q&1,q>>=1;for(t=l;t<f;t+=k)e[t]=g<<16|p;++h}++g;h<<=1;k<<=1}return[e,a,c]};function w(b,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=u?new Uint8Array(b):b;this.m=!1;this.i=x;this.r=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.r=d.resize);switch(this.i){case y:this.b=32768;this.c=new (u?Uint8Array:Array)(32768+this.h+258);break;case x:this.b=0;this.c=new (u?Uint8Array:Array)(this.h);this.e=this.z;this.n=this.v;this.j=this.w;break;default:m(Error("invalid inflate mode"))}}
var y=0,x=1,z={t:y,s:x};
w.prototype.k=function(){for(;!this.m;){var b=A(this,3);b&1&&(this.m=!0);b>>>=1;switch(b){case 0:var d=this.input,a=this.a,c=this.c,f=this.b,e=n,g=n,h=n,k=c.length,l=n;this.d=this.f=0;e=d[a++];e===n&&m(Error("invalid uncompressed block header: LEN (first byte)"));g=e;e=d[a++];e===n&&m(Error("invalid uncompressed block header: LEN (second byte)"));g|=e<<8;e=d[a++];e===n&&m(Error("invalid uncompressed block header: NLEN (first byte)"));h=e;e=d[a++];e===n&&m(Error("invalid uncompressed block header: NLEN (second byte)"));h|=
e<<8;g===~h&&m(Error("invalid uncompressed block header: length verify"));a+g>d.length&&m(Error("input buffer is broken"));switch(this.i){case y:for(;f+g>c.length;){l=k-f;g-=l;if(u)c.set(d.subarray(a,a+l),f),f+=l,a+=l;else for(;l--;)c[f++]=d[a++];this.b=f;c=this.e();f=this.b}break;case x:for(;f+g>c.length;)c=this.e({p:2});break;default:m(Error("invalid inflate mode"))}if(u)c.set(d.subarray(a,a+g),f),f+=g,a+=g;else for(;g--;)c[f++]=d[a++];this.a=a;this.b=f;this.c=c;break;case 1:this.j(B,C);break;case 2:aa(this);
break;default:m(Error("unknown BTYPE: "+b))}}return this.n()};
var D=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],E=u?new Uint16Array(D):D,F=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],G=u?new Uint16Array(F):F,H=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],I=u?new Uint8Array(H):H,J=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],K=u?new Uint16Array(J):J,L=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,
13],M=u?new Uint8Array(L):L,N=new (u?Uint8Array:Array)(288),O,P;O=0;for(P=N.length;O<P;++O)N[O]=143>=O?8:255>=O?9:279>=O?7:8;var B=v(N),Q=new (u?Uint8Array:Array)(30),R,S;R=0;for(S=Q.length;R<S;++R)Q[R]=5;var C=v(Q);function A(b,d){for(var a=b.f,c=b.d,f=b.input,e=b.a,g;c<d;)g=f[e++],g===n&&m(Error("input buffer is broken")),a|=g<<c,c+=8;g=a&(1<<d)-1;b.f=a>>>d;b.d=c-d;b.a=e;return g}
function T(b,d){for(var a=b.f,c=b.d,f=b.input,e=b.a,g=d[0],h=d[1],k,l,q;c<h;){k=f[e++];if(k===n)break;a|=k<<c;c+=8}l=g[a&(1<<h)-1];q=l>>>16;b.f=a>>q;b.d=c-q;b.a=e;return l&65535}
function aa(b){function d(a,b,c){var d,e,f,g;for(g=0;g<a;)switch(d=T(this,b),d){case 16:for(f=3+A(this,2);f--;)c[g++]=e;break;case 17:for(f=3+A(this,3);f--;)c[g++]=0;e=0;break;case 18:for(f=11+A(this,7);f--;)c[g++]=0;e=0;break;default:e=c[g++]=d}return c}var a=A(b,5)+257,c=A(b,5)+1,f=A(b,4)+4,e=new (u?Uint8Array:Array)(E.length),g,h,k,l;for(l=0;l<f;++l)e[E[l]]=A(b,3);g=v(e);h=new (u?Uint8Array:Array)(a);k=new (u?Uint8Array:Array)(c);b.j(v(d.call(b,a,g,h)),v(d.call(b,c,g,k)))}
w.prototype.j=function(b,d){var a=this.c,c=this.b;this.o=b;for(var f=a.length-258,e,g,h,k;256!==(e=T(this,b));)if(256>e)c>=f&&(this.b=c,a=this.e(),c=this.b),a[c++]=e;else{g=e-257;k=G[g];0<I[g]&&(k+=A(this,I[g]));e=T(this,d);h=K[e];0<M[e]&&(h+=A(this,M[e]));c>=f&&(this.b=c,a=this.e(),c=this.b);for(;k--;)a[c]=a[c++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=c};
w.prototype.w=function(b,d){var a=this.c,c=this.b;this.o=b;for(var f=a.length,e,g,h,k;256!==(e=T(this,b));)if(256>e)c>=f&&(a=this.e(),f=a.length),a[c++]=e;else{g=e-257;k=G[g];0<I[g]&&(k+=A(this,I[g]));e=T(this,d);h=K[e];0<M[e]&&(h+=A(this,M[e]));c+k>f&&(a=this.e(),f=a.length);for(;k--;)a[c]=a[c++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=c};
w.prototype.e=function(){var b=new (u?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,c,f=this.c;if(u)b.set(f.subarray(32768,b.length));else{a=0;for(c=b.length;a<c;++a)b[a]=f[a+32768]}this.g.push(b);this.l+=b.length;if(u)f.set(f.subarray(d,d+32768));else for(a=0;32768>a;++a)f[a]=f[d+a];this.b=32768;return f};
w.prototype.z=function(b){var d,a=this.input.length/this.a+1|0,c,f,e,g=this.input,h=this.c;b&&("number"===typeof b.p&&(a=b.p),"number"===typeof b.u&&(a+=b.u));2>a?(c=(g.length-this.a)/this.o[2],e=258*(c/2)|0,f=e<h.length?h.length+e:h.length<<1):f=h.length*a;u?(d=new Uint8Array(f),d.set(h)):d=h;return this.c=d};
w.prototype.n=function(){var b=0,d=this.c,a=this.g,c,f=new (u?Uint8Array:Array)(this.l+(this.b-32768)),e,g,h,k;if(0===a.length)return u?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);e=0;for(g=a.length;e<g;++e){c=a[e];h=0;for(k=c.length;h<k;++h)f[b++]=c[h]}e=32768;for(g=this.b;e<g;++e)f[b++]=d[e];this.g=[];return this.buffer=f};
w.prototype.v=function(){var b,d=this.b;u?this.r?(b=new Uint8Array(d),b.set(this.c.subarray(0,d))):b=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),b=this.c);return this.buffer=b};function U(b,d){var a,c;this.input=b;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=b[this.a++];c=b[this.a++];switch(a&15){case V:this.method=V;break;default:m(Error("unsupported compression method"))}0!==((a<<8)+c)%31&&m(Error("invalid fcheck flag:"+((a<<8)+c)%31));c&32&&m(Error("fdict flag is not supported"));this.q=new w(b,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
U.prototype.k=function(){var b=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(b[this.a++]<<24|b[this.a++]<<16|b[this.a++]<<8|b[this.a++])>>>0;var c=d;if("string"===typeof c){var f=c.split(""),e,g;e=0;for(g=f.length;e<g;e++)f[e]=(f[e].charCodeAt(0)&255)>>>0;c=f}for(var h=1,k=0,l=c.length,q,p=0;0<l;){q=1024<l?1024:l;l-=q;do h+=c[p++],k+=h;while(--q);h%=65521;k%=65521}a!==(k<<16|h)>>>0&&m(Error("invalid adler-32 checksum"))}return d};var V=8;s("Zlib.Inflate",U);s("Zlib.Inflate.prototype.decompress",U.prototype.k);var W={ADAPTIVE:z.s,BLOCK:z.t},X,Y,Z,$;if(Object.keys)X=Object.keys(W);else for(Y in X=[],Z=0,W)X[Z++]=Y;Z=0;for($=X.length;Z<$;++Z)Y=X[Z],s("Zlib.Inflate.BufferType."+Y,W[Y]);}).call(this);
function Log(msg)
{
if (window.console && console.log)
console.log(msg); //for firebug
}
var lastCommand;
function Char(p, ch)
{
if(p.pos < p.data.length && (255 & p.data[p.pos]) == ch) {
lastCommand = ch;
p.pos++;
return true;
}
return false;
}
function Get8(p)
{
return p.pos < p.data.length ? (255 & p.data[p.pos++]) : 0;
}
function Get16(p)
{
var l = Get8(p);
var h = Get8(p);
return (h << 8) | l;
}
function Get32(p)
{
var l = Get16(p);
var h = Get16(p);
return (h << 16) | l;
}
var lastLen; // TODO: remove
var lastString;
function GetString(p)
{
var n = Get32(p);
lastLen = n;
var s = "";
for(var i = 0; i < n; i++)
s += String.fromCharCode(Get8(p));
lastString = s;
return s;
}
var SendingEnabled = true;
var posx, posy;
var ctx;
var caretx = 0, carety = 0, caretcx = 0, caretcy = 0, caretshown = false;
var caretTimerID;
function InvertRect(x, y, cx, cy)
{
if(cx <= 0 || cy <= 0)
return;
var imageData = ctx.getImageData(x, y, cx, cy);
var data = imageData.data;
for(var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i];
data[i + 1] = 255 - data[i + 1];
data[i + 2] = 255 - data[i + 2];
}
ctx.putImageData(imageData, x, y);
}
function DrawDragLine(x, y, cx, cy, anim)
{
if(cx <= 0 || cy <= 0)
return;
var imageData = ctx.getImageData(x, y, cx, cy);
var data = imageData.data;
for(var i = 0; i < data.length; i += 4) {
if(((i / 4 + anim) / 4) & 1) {
data[i] = 255 - data[i];
data[i + 1] = 255 - data[i + 1];
data[i + 2] = 255 - data[i + 2];
}
}
ctx.putImageData(imageData, x, y);
}
function InvertCaret()
{
// Log("InvertCaret " + caretx + " " + carety + " " + caretcx + " " + caretcy);
if(caretcx >= 0 || caretcy >= 0)
InvertRect(caretx, carety, caretcx, caretcy);
}
function ClearCaretTimer()
{
if(caretTimerID != undefined)
clearTimeout(caretTimerID);
}
function CaretTimer()
{
ClearCaretTimer();
caretTimerID = setTimeout(DoCaret, 500);
}
function DoCaret()
{
if(caretcx || caretcy) {
InvertCaret();
caretshown = !caretshown;
CaretTimer();
}
}
function InvertShownCaret()
{
if(caretshown)
InvertCaret();
}
function HideCaret(x, y, cx, cy)
{
return;
if(caretHidden)
return;
if(Math.max(x, caretx) < Math.min(x + cx, caretx + caretcx) &&
Math.max(y, carety) < Math.min(y + cy, carety + caretcy)) {
// Log("Hiding caret");
InvertShownCaret();
caretHidden = true;
}
}
var lastR, lastG, lastB;
function SetFillColor(r, g, b)
{
if(r == lastR && g == lastG && b == lastB)
return;
lastR = r;
lastG = g;
lastB = b;
var c = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillStyle = c;
}
function ProcessDraw(s)
{
// console.clear();
// Log("Painting started " + s.length);
// window.document.title = "Processing draw";
var time0 = (new Date).getTime();
var p = new Object;
p.data = s;
p.pos = 0;
var canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
SendingEnabled = true;
posx = 0;
posy = 0;
InvertShownCaret();
while(p.pos < p.data.length) {
// Log(p.pos + ": " + p.data[p.pos]);
if(Char(p, 0)) { // RECT
var x = Get16(p);
var y = Get16(p);
var cx = Get16(p);
var cy = Get16(p);
var r = Get8(p);
var g = Get8(p);
var b = Get8(p);
SetFillColor(r, g, b);
// Log("color: " + c);
HideCaret(x, y, cx, cy);
ctx.fillRect(x, y, cx, cy);
posx = x;
posy = y;
}
else
if(Char(p, 3)) { // INVERTRECT
var x = Get16(p);
var y = Get16(p);
var cx = Get16(p);
var cy = Get16(p);
// Log("irect: " + x + ", " + y + ", " + cx + ", " + cy);
HideCaret(x, y, cx, cy);
InvertRect(x, y, cx, cy);
posx = x;
posy = y;
}
else
if(Char(p, 2)) { // SETIMAGE
var r = Get16(p);
var cx = Get16(p);
var cy = Get16(p);
var n = cx * cy * 4;
var imgData = ctx.createImageData(cx, cy);
for(i = 0; i < n; i++)
imgData.data[i] = Get8(p);
var img = document.createElement('canvas');
img.width = cx;
img.height = cy;
img.getContext("2d").putImageData(imgData, 0, 0);
window.img_cache[r] = img;
// Log("Set image: " + r);
if(img == undefined) // TODO: Remove after debugging this
alert("Undefined in set: " + n);
if(window.img_cache[r] == undefined)
alert("Undefined 2: " + n);
}
else
if(Char(p, 1)) { // IMAGE
var n = Get16(p);
var px = Get16(p);
var py = Get16(p);
var x = Get16(p);
var y = Get16(p);
var cx = Get16(p);
var cy = Get16(p);
// Log("Draw image: " + n);
if(window.img_cache[n] == undefined)
alert("Undefined image: " + n);
HideCaret(x, y, cx, cy);
ctx.drawImage(window.img_cache[n], x, y, cx, cy, px, py, cx, cy);
posx = px;
posy = py;
}
else
if(Char(p, 4)) { // STD_CURSORIMAGE
canvas.style.cursor = [
"default", // should not happen
"default", // Arrow
"wait", // Wait
"text", // IBeam
"not-allowed", // No
"move", // SizeAll
"ew-resize", // SizeHorz
"ns-resize", // SizeVert
"nw-resize", // SizeTopLeft
"n-resize", // SizeTop
"ne-resize", // SizeTopRight
"w-resize", // SizeLeft
"e-resize", // SizeRight
"sw-resize", // SizeBottomLeft
"s-resize", // SizeBottom
"se-resize", // SizeBottomRight
"pointer" // Hand
][Get8(p)];
}
else
if(Char(p, 5)) { // SETCURSORIMAGE
i = Get16(p);
window.cursor_cache[i] = GetString(p);
}
else
if(Char(p, 6)) { // CURSORIMAGE
i = Get16(p);
canvas.style.cursor = window.cursor_cache[i];
// Log(cursor_cache[i]);
}
else
if(Char(p, 7)) { // DISABLESENDING
SendingEnabled = true;
}
else
if(Char(p, 8)) { // UPDATESERIAL
update_serial_l = Get32(p);
update_serial_h = Get32(p);
ws.send("S " + update_serial_l + " " + update_serial_h + " " + ((new Date).getTime() - time0) + "\n");
}
else
if(Char(p, 9)) // IMAGEPP
SImage(p, 1, 1);
else
if(Char(p, 10)) // IMAGENP
SImage(p, -1, 1);
else
if(Char(p, 11)) // IMAGEPN
SImage(p, 1, -1);
else
if(Char(p, 12)) // IMAGENN
SImage(p, -1, -1);
else
if(Char(p, 13)) // RECTPP
SRect(p, 1, 1);
else
if(Char(p, 14)) // RECTNP
SRect(p, -1, 1);
else
if(Char(p, 15)) // RECTPN
SRect(p, 1, -1);
else
if(Char(p, 16)) // RECTNN
SRect(p, -1, -1);
else
if(Char(p, 17)) { // SETCARET
caretx = Get16(p);
carety = Get16(p);
caretcx = Get16(p);
caretcy = Get16(p);
caretshown = true;
CaretTimer();
// Log("SET CARET " + caretx + " " + carety + " " + caretcx + " " + caretcy);
}
else
if(Char(p, 18)) { // HORZDRAGLINE,
var x = Get16(p);
var y = Get16(p);
var l = Get16(p);
var anim = Get16(p);
DrawDragLine(x, y, l, 1, anim);
}
else
if(Char(p, 19)) { // VERTDRAGLINE,
var x = Get16(p);
var y = Get16(p);
var l = Get16(p);
var anim = Get16(p);
DrawDragLine(x, y, 1, l, anim);
}
else
if(Char(p, 20)) { // OPENLINK,
var s = GetString(p);
window.open(s);
}
else {
alert("Unrecognized code: " + p.data[p.pos] + " after " + lastCommand + " lastLen " + lastLen + " lastString " + lastString);
break;
}
}
InvertShownCaret();
// window.document.title = "OK";
if(SendingEnabled && event_queue.length)
ScheduleSend();
// Log("Painting finished");
}
function SImage(p, sx, sy)
{
var px = posx + sx * Get8(p);
var py = posy + sy * Get8(p);
var n = Get16(p);
// Log("Draw opt image: " + px + " " + py + " " + n);
var img = window.img_cache[n];
if(img == undefined)
alert("Undefined image: " + n);
HideCaret(px, py, img.width, img.height);
ctx.drawImage(window.img_cache[n], px, py);
posx = px;
posy = py;
}
function SRect(p, sx, sy)
{
var px = posx + sx * Get8(p);
var py = posy + sy * Get8(p);
var cx = Get8(p);
var cy = Get8(p);
var r = Get8(p);
var g = Get8(p);
var b = Get8(p);
// Log("rect: " + x + ", " + y + ", " + cx + ", " + cy);
SetFillColor(r, g, b);
// Log("color: " + c);
HideCaret(x, y, cx, cy);
ctx.fillRect(x, y, cx, cy);
posx = px;
posy = py;
}
window.img_cache = {};
window.event_queue = "i\n";
window.cursor_cache = {};
window.update_serial_l = 0;
window.update_serial_h = 0;
var canvas = document.getElementById("myCanvas");
function key_flags(event)
{
return " " + 1*event.shiftKey + 1*event.ctrlKey + 1*event.altKey + "\n";
}
function mouse_event(event)
{
return " " + event.clientX + " " + event.clientY + " " + (new Date).getTime() + key_flags(event);
}
canvas.onmousemove = function(event)
{
event_queue += "M" + mouse_event(event);
ScheduleSend();
event.preventDefault();
}
canvas.onmousedown = function(event)
{
event_queue += "D " + event.button + mouse_event(event);
ScheduleSend();
event.preventDefault();
}
canvas.onmouseout = function(event)
{
event_queue += "O\n";
ScheduleSend();
event.preventDefault();
}
canvas.onmouseover = function(event)
{
event_queue += "I\n";
ScheduleSend();
event.preventDefault();
}
canvas.onmouseup = function(event)
{
event_queue += "U " + event.button + mouse_event(event);
ScheduleSend();
event.preventDefault();
}
function MouseWheel(event)
{
event_queue += "W " + event.deltaY + mouse_event(event);
}
canvas.addEventListener("wheel", MouseWheel); // IE9 needs addEventListener...
document.onkeydown = function(event)
{
event_queue += "K " + event.keyCode + " " + event.which + key_flags(event);
ScheduleSend();
if(event.ctrlKey || event.altKey || event.keyCode == 8 || event.keyCode == 9) {
event.stopPropagation();
event.preventDefault();
}
}
document.onkeypress = function(event)
{
event_queue += "C " + event.keyCode + " " + event.which + key_flags(event);
event.preventDefault();
ScheduleSend();
event.stopPropagation();
event.preventDefault();
}
document.onkeyup = function(event)
{
event_queue += "k " + event.keyCode + " " + event.which + key_flags(event);
event.preventDefault();
ScheduleSend();
if(event.ctrlKey || event.altKey) {
event.stopPropagation();
event.preventDefault();
}
}
function ResizeCanvas()
{
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
event_queue += "R " + canvas.width + ' ' + canvas.height + "\n";
ScheduleSend();
}
window.onresize = ResizeCanvas;
var timerID;
function ConnectWebsocket()
{
return new WebSocket("%%host%%");
}
var ws = ConnectWebsocket();
ws.binaryType = "arraybuffer";
function ScheduleSend()
{
if(SendingEnabled) {
if(timerID != undefined)
clearTimeout(timerID);
timerID = setTimeout(SendEvents, 0);
}
}
function SendEvents()
{
if(SendingEnabled) {
if(event_queue.length) {
// Log(event_queue);
ws.send(event_queue);
}
else
ws.send("PING");
event_queue = "";
if(timerID != undefined)
clearTimeout(timerID);
timerID = setTimeout(SendEvents, 20);
}
}
ws.onopen = function()
{
// Log("websocket connection opened");
ResizeCanvas();
};
ws.onmessage = function(event)
{
// Log("onmessage");
if(event.data instanceof ArrayBuffer) {
var inflate = new Zlib.Inflate(new Uint8Array(event.data));
ProcessDraw(inflate.decompress());
}
};
ws.onclose = function(ev)
{
ClearCaretTimer();
alert("Connection closed.");
};
</script>
</body>
</html>