You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
11 KiB
JavaScript
431 lines
11 KiB
JavaScript
/*global Quintus:false */
|
|
|
|
Quintus.UI = function(Q) {
|
|
if(Q._isUndefined(Quintus.Touch)) {
|
|
throw "Quintus.UI requires Quintus.Touch Module";
|
|
}
|
|
|
|
Q.UI = {};
|
|
|
|
// Draw a rounded rectangle centered on 0,0
|
|
Q.UI.roundRect = function(ctx, rect) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(-rect.cx + rect.radius, -rect.cy);
|
|
ctx.lineTo(-rect.cx + rect.w - rect.radius, -rect.cy);
|
|
ctx.quadraticCurveTo(-rect.cx + rect.w, -rect.cy, -rect.cx + rect.w, -rect.cy + rect.radius);
|
|
ctx.lineTo(-rect.cx + rect.w, -rect.cy + rect.h - rect.radius);
|
|
ctx.quadraticCurveTo(-rect.cx + rect.w,
|
|
-rect.cy + rect.h,
|
|
-rect.cx + rect.w - rect.radius,
|
|
-rect.cy + rect.h);
|
|
ctx.lineTo(-rect.cx + rect.radius, -rect.cy + rect.h);
|
|
ctx.quadraticCurveTo(-rect.cx, -rect.cy + rect.h, -rect.cx, -rect.cy + rect.h - rect.radius);
|
|
ctx.lineTo(-rect.cx, -rect.cy + rect.radius);
|
|
ctx.quadraticCurveTo(-rect.cx, -rect.cy, -rect.cx + rect.radius, -rect.cy);
|
|
ctx.closePath();
|
|
};
|
|
|
|
|
|
|
|
Q.UI.Container = Q.Sprite.extend("UI.Container", {
|
|
init: function(p,defaults) {
|
|
var adjustedP = Q._clone(p||{}),
|
|
match;
|
|
|
|
if(p && Q._isString(p.w) && (match = p.w.match(/^[0-9]+%$/))) {
|
|
adjustedP.w = parseInt(p.w,10) * Q.width / 100;
|
|
adjustedP.x = Q.width/2 - adjustedP.w/2;
|
|
}
|
|
|
|
if(p && Q._isString(p.h) && (match = p.h.match(/^[0-9]+%$/))) {
|
|
adjustedP.h = parseInt(p.h,10) * Q.height / 100;
|
|
adjustedP.y = Q.height /2 - adjustedP.h/2;
|
|
}
|
|
|
|
this._super(Q._defaults(adjustedP,defaults),{
|
|
opacity: 1,
|
|
hidden: false, // Set to true to not show the container
|
|
fill: null, // Set to color to add background
|
|
highlight: null, // Set to color to for button
|
|
radius: 5, // Border radius
|
|
stroke: "#000",
|
|
border: false, // Set to a width to show a border
|
|
shadow: false, // Set to true or a shadow offest
|
|
shadowColor: false, // Set to a rgba value for the shadow
|
|
type: Q.SPRITE_NONE
|
|
});
|
|
|
|
},
|
|
|
|
insert: function(obj) {
|
|
this.stage.insert(obj,this);
|
|
return obj;
|
|
},
|
|
|
|
fit: function(paddingY,paddingX) {
|
|
if(this.children.length === 0) { return; }
|
|
|
|
if(paddingY === void 0) { paddingY = 0; }
|
|
if(paddingX === void 0) { paddingX = paddingY; }
|
|
|
|
var minX = Infinity,
|
|
minY = Infinity,
|
|
maxX = -Infinity,
|
|
maxY = -Infinity;
|
|
|
|
for(var i =0;i < this.children.length;i++) {
|
|
var obj = this.children[i];
|
|
var minObjX = obj.p.x - obj.p.cx,
|
|
minObjY = obj.p.y - obj.p.cy,
|
|
maxObjX = obj.p.x - obj.p.cx + obj.p.w,
|
|
maxObjY = obj.p.y - obj.p.cy + obj.p.h;
|
|
|
|
if(minObjX < minX) { minX = minObjX; }
|
|
if(minObjY < minY) { minY = minObjY; }
|
|
|
|
if(maxObjX > maxX) { maxX = maxObjX; }
|
|
if(maxObjY > maxY) { maxY = maxObjY; }
|
|
|
|
}
|
|
|
|
this.p.cx = -minX + paddingX;
|
|
this.p.cy = -minY + paddingY;
|
|
this.p.w = maxX - minX + paddingX * 2;
|
|
this.p.h = maxY - minY + paddingY * 2;
|
|
},
|
|
|
|
addShadow: function(ctx) {
|
|
if(this.p.shadow) {
|
|
var shadowAmount = Q._isNumber(this.p.shadow) ? this.p.shadow : 5;
|
|
ctx.shadowOffsetX=shadowAmount;
|
|
ctx.shadowOffsetY=shadowAmount;
|
|
ctx.shadowColor = this.p.shadowColor || "rgba(0,0,50,0.1)";
|
|
}
|
|
},
|
|
|
|
clearShadow: function(ctx) {
|
|
ctx.shadowColor = "transparent";
|
|
},
|
|
|
|
drawRadius: function(ctx) {
|
|
Q.UI.roundRect(ctx,this.p);
|
|
this.addShadow(ctx);
|
|
ctx.fill();
|
|
if(this.p.border) {
|
|
this.clearShadow(ctx);
|
|
ctx.lineWidth = this.p.border;
|
|
ctx.stroke();
|
|
}
|
|
},
|
|
|
|
drawSquare: function(ctx) {
|
|
this.addShadow(ctx);
|
|
if(this.p.fill) {
|
|
ctx.fillRect(-this.p.cx,-this.p.cy,
|
|
this.p.w,this.p.h);
|
|
}
|
|
|
|
if(this.p.border) {
|
|
this.clearShadow(ctx);
|
|
ctx.lineWidth = this.p.border;
|
|
ctx.strokeRect(-this.p.cx,-this.p.cy,
|
|
this.p.w,this.p.h);
|
|
}
|
|
},
|
|
|
|
draw: function(ctx) {
|
|
if(this.p.hidden) { return false; }
|
|
if(!this.p.border && !this.p.fill) { return; }
|
|
|
|
ctx.globalAlpha = this.p.opacity;
|
|
if(this.p.frame === 1 && this.p.highlight) {
|
|
ctx.fillStyle = this.p.highlight;
|
|
} else {
|
|
ctx.fillStyle = this.p.fill;
|
|
}
|
|
ctx.strokeStyle = this.p.stroke;
|
|
|
|
if(this.p.radius > 0) {
|
|
this.drawRadius(ctx);
|
|
} else {
|
|
this.drawSquare(ctx);
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
|
|
Q.UI.Text = Q.Sprite.extend("UI.Text", {
|
|
init: function(p,defaultProps) {
|
|
this._super(Q._defaults(p||{},defaultProps),{
|
|
type: Q.SPRITE_UI,
|
|
size: 24
|
|
});
|
|
|
|
//this.el = document.createElement("canvas");
|
|
//this.ctx = this.el.getContext("2d");
|
|
|
|
if(this.p.label) {
|
|
this.calcSize();
|
|
}
|
|
|
|
//this.prerender();
|
|
},
|
|
|
|
calcSize: function() {
|
|
this.setFont(Q.ctx);
|
|
this.splitLabel = this.p.label.split("\n");
|
|
var maxLabel = "";
|
|
for(var i = 0;i < this.splitLabel.length;i++) {
|
|
if(this.splitLabel[i].length > maxLabel.length) {
|
|
maxLabel = this.splitLabel[i];
|
|
}
|
|
}
|
|
|
|
var metrics = Q.ctx.measureText(maxLabel);
|
|
this.p.h = (this.p.size || 24) * this.splitLabel.length * 1.2;
|
|
this.p.w = metrics.width;
|
|
this.p.cx = this.p.w / 2;
|
|
this.p.cy = this.p.h / 2;
|
|
},
|
|
|
|
prerender: function() {
|
|
if(this.p.oldLabel === this.p.label) { return; }
|
|
this.p.oldLabel = this.p.label;
|
|
this.calcSize();
|
|
this.el.width = this.p.w;
|
|
this.el.height = this.p.h * 4;
|
|
this.ctx.clearRect(0,0,this.p.w,this.p.h);
|
|
|
|
this.ctx.fillStyle = "#FF0";
|
|
this.ctx.fillRect(0,0,this.p.w,this.p.h/2);
|
|
this.setFont(this.ctx);
|
|
|
|
this.ctx.fillText(this.p.label,0,0);
|
|
},
|
|
|
|
draw: function(ctx) {
|
|
//this.prerender();
|
|
if(this.p.opacity === 0) { return; }
|
|
|
|
if(this.p.oldLabel !== this.p.label) { this.calcSize(); }
|
|
|
|
this.setFont(ctx);
|
|
if(this.p.opacity !== void 0) { ctx.globalAlpha = this.p.opacity; }
|
|
for(var i =0;i<this.splitLabel.length;i++) {
|
|
if(this.p.align === 'center') {
|
|
ctx.fillText(this.splitLabel[i],0,-this.p.cy + i * this.p.size * 1.2);
|
|
} else if(this.p.align === 'right') {
|
|
ctx.fillText(this.splitLabel[i],this.p.cx,-this.p.cy + i * this.p.size * 1.2);
|
|
} else {
|
|
ctx.fillText(this.splitLabel[i],-this.p.cx,-this.p.cy +i * this.p.size * 1.2);
|
|
}
|
|
}
|
|
},
|
|
|
|
asset: function() {
|
|
return this.el;
|
|
},
|
|
|
|
setFont: function(ctx) {
|
|
ctx.textBaseline = "top";
|
|
ctx.font= this.font();
|
|
ctx.fillStyle = this.p.color || "black";
|
|
ctx.textAlign = this.p.align || "left";
|
|
},
|
|
|
|
font: function() {
|
|
if(this.fontString) { return this.fontString; }
|
|
|
|
this.fontString = (this.p.weight || "800") + " " +
|
|
(this.p.size || 24) + "px " +
|
|
(this.p.family || "Arial");
|
|
|
|
return this.fontString;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
Q.UI.Button = Q.UI.Container.extend("UI.Button", {
|
|
init: function(p,callback) {
|
|
this._super(Q._defaults(p,{
|
|
type: Q.SPRITE_UI | Q.SPRITE_DEFAULT
|
|
}));
|
|
if(this.p.label && (!this.p.w || !this.p.h)) {
|
|
Q.ctx.save();
|
|
this.setFont(Q.ctx);
|
|
var metrics = Q.ctx.measureText(this.p.label);
|
|
Q.ctx.restore();
|
|
if(!this.p.h) { this.p.h = 24 + 20; }
|
|
if(!this.p.w) { this.p.w = metrics.width + 20; }
|
|
}
|
|
|
|
if(isNaN(this.p.cx)) { this.p.cx = this.p.w / 2; }
|
|
if(isNaN(this.p.cy)) { this.p.cy = this.p.h / 2; }
|
|
this.callback = callback;
|
|
this.on('touch',this,"highlight");
|
|
this.on('touchEnd',this,"push");
|
|
},
|
|
|
|
highlight: function() {
|
|
if(!this.sheet() || this.sheet().frames > 1) {
|
|
this.p.frame = 1;
|
|
}
|
|
},
|
|
|
|
push: function() {
|
|
this.p.frame = 0;
|
|
if(this.callback) { this.callback(); }
|
|
this.trigger('click');
|
|
},
|
|
|
|
draw: function(ctx) {
|
|
this._super(ctx);
|
|
|
|
if(this.p.asset || this.p.sheet) {
|
|
Q.Sprite.prototype.draw.call(this,ctx);
|
|
}
|
|
|
|
if(this.p.label) {
|
|
ctx.save();
|
|
this.setFont(ctx);
|
|
ctx.fillText(this.p.label,0,0);
|
|
ctx.restore();
|
|
}
|
|
},
|
|
|
|
setFont: function(ctx) {
|
|
ctx.textBaseline = "middle";
|
|
ctx.font = this.p.font || "400 24px arial";
|
|
ctx.fillStyle = this.p.fontColor || "black";
|
|
ctx.textAlign = "center";
|
|
}
|
|
|
|
});
|
|
|
|
Q.UI.IFrame = Q.Sprite.extend("UI.IFrame", {
|
|
init: function(p) {
|
|
this._super(p, { opacity: 1, type: Q.SPRITE_UI | Q.SPRITE_DEFAULT });
|
|
|
|
Q.wrapper.style.overflow = "hidden";
|
|
|
|
this.iframe = document.createElement("IFRAME");
|
|
this.iframe.setAttribute("src",this.p.url);
|
|
this.iframe.style.position = "absolute";
|
|
this.iframe.style.zIndex = 500;
|
|
this.iframe.setAttribute("width",this.p.w);
|
|
this.iframe.setAttribute("height",this.p.h);
|
|
this.iframe.setAttribute("frameborder",0);
|
|
|
|
if(this.p.background) {
|
|
this.iframe.style.backgroundColor = this.p.background;
|
|
|
|
}
|
|
|
|
|
|
Q.wrapper.appendChild(this.iframe);
|
|
this.on("inserted",function(parent) {
|
|
this.positionIFrame();
|
|
parent.on("destroyed",this,"remove");
|
|
});
|
|
},
|
|
|
|
positionIFrame: function() {
|
|
var x = this.p.x;
|
|
var y = this.p.y;
|
|
if(this.stage.viewport) {
|
|
x -= this.stage.viewport.x;
|
|
y -= this.stage.viewport.y;
|
|
}
|
|
|
|
if(this.oldX !== x || this.oldY !== y || this.oldOpacity !== this.p.opacity) {
|
|
|
|
this.iframe.style.top = (y - this.p.cy) + "px";
|
|
this.iframe.style.left = (x - this.p.cx) + "px";
|
|
this.iframe.style.opacity = this.p.opacity;
|
|
|
|
this.oldX = x;
|
|
this.oldY = y;
|
|
this.oldOpacity = this.p.opacity;
|
|
}
|
|
},
|
|
|
|
step: function(dt) {
|
|
this._super(dt);
|
|
this.positionIFrame();
|
|
},
|
|
|
|
remove: function() {
|
|
if(this.iframe) {
|
|
Q.wrapper.removeChild(this.iframe);
|
|
this.iframe = null;
|
|
}
|
|
}
|
|
});
|
|
|
|
Q.UI.HTMLElement = Q.Sprite.extend("UI.HTMLElement", {
|
|
init: function(p) {
|
|
this._super(p, { opacity: 1, type: Q.SPRITE_UI });
|
|
|
|
Q.wrapper.style.overflow = "hidden";
|
|
|
|
this.el = document.createElement("div");
|
|
this.el.innerHTML = this.p.html;
|
|
|
|
Q.wrapper.appendChild(this.el);
|
|
this.on("inserted",function(parent) {
|
|
this.position();
|
|
parent.on("destroyed",this,"remove");
|
|
parent.on("clear",this,"remove");
|
|
});
|
|
},
|
|
|
|
position: function() {
|
|
},
|
|
|
|
step: function(dt) {
|
|
this._super(dt);
|
|
this.position();
|
|
},
|
|
|
|
remove: function() {
|
|
if(this.el) {
|
|
Q.wrapper.removeChild(this.el);
|
|
this.el= null;
|
|
}
|
|
}
|
|
});
|
|
|
|
Q.UI.VerticalLayout = Q.Sprite.extend("UI.VerticalLayout",{
|
|
|
|
|
|
init: function(p) {
|
|
this.children = [];
|
|
this._super(p, { type: 0 });
|
|
},
|
|
|
|
insert: function(sprite) {
|
|
this.stage.insert(sprite,this);
|
|
this.relayout();
|
|
// Bind to destroy
|
|
return sprite;
|
|
},
|
|
|
|
relayout: function() {
|
|
var totalHeight = 0;
|
|
for(var i=0;i<this.children.length;i++) {
|
|
totalHeight += this.children[i].p.h || 0;
|
|
}
|
|
|
|
// Center?
|
|
var totalSepartion = this.p.h - totalHeight;
|
|
|
|
// Make sure all elements have the same space between them
|
|
}
|
|
});
|
|
|
|
|
|
|
|
};
|