add modified p5.clickable

This commit is contained in:
nadiarvi 2025-04-30 17:25:55 +09:00
parent ecd0f710df
commit 7bc18dab67

248
lib/p5.clickable.js Normal file
View File

@ -0,0 +1,248 @@
//Determines if the mouse was pressed on the previous frame
var cl_mouseWasPressed = false;
//Last hovered button
var cl_lastHovered = null;
//Last pressed button
var cl_lastClicked = null;
//All created buttons
var cl_clickables = [];
//This function is what makes the magic happen and should be ran after
//each draw cycle.
p5.prototype.runGUI = function () {
for (i = 0; i < cl_clickables.length; ++i) {
if (cl_lastHovered != cl_clickables[i])
cl_clickables[i].onOutside();
}
if (cl_lastHovered != null) {
if (cl_lastClicked != cl_lastHovered) {
cl_lastHovered.onHover();
}
}
if (!cl_mouseWasPressed && cl_lastClicked != null) {
cl_lastClicked.onPress();
}
if (cl_mouseWasPressed && !mouseIsPressed && cl_lastClicked != null) {
if (cl_lastClicked == cl_lastHovered) {
cl_lastClicked.onRelease();
}
cl_lastClicked = null;
}
cl_lastHovered = null;
cl_mouseWasPressed = mouseIsPressed;
}
p5.prototype.registerMethod('post', p5.prototype.runGUI);
//This function is used to get the bounding size of a
//string of text for use in the 'textScaled' property
function getTextBounds(m, font, size) {
let txt = document.createElement("span");
document.body.appendChild(txt);
txt.style.font = font;
txt.style.fontSize = size + "px";
txt.style.height = 'auto';
txt.style.width = 'auto';
txt.style.position = 'absolute';
txt.style.whiteSpace = 'no-wrap';
txt.innerHTML = m;
let width = Math.ceil(txt.clientWidth);
let height = Math.ceil(txt.clientHeight);
document.body.removeChild(txt);
return [width, height];
}
//Button Class
function Clickable(x,y) {
this.x = x; //X position of the clickable
this.y = y; //Y position of the clickable
this.width = 100; //Width of the clickable
this.height = 50; //Height of the clickable
this.color = "#FFFFFF"; //Background color of the clickable
this.cornerRadius = 10; //Corner radius of the clickable
this.strokeWeight = 2; //Stroke width of the clickable
this.stroke = "#000000"; //Border color of the clickable
this.text = "Press Me"; //Text of the clickable
this.textColor = "#000000"; //Color for the text shown
this.textSize = 12; //Size for the text shown
this.textFont = "sans-serif"; //Font for the text shown
this.textScaled = false; //Scale the text with the size of the clickable
// image options
this.image = null; // image object from p5loadimage()
this.fitImage = false; // when true, image will stretch to fill button
this.imageScale = 1.0;
this.tint = null; // tint image using color
this.noTint = true; // default to disable tinting
this.filter = null; // filter effect
// MODIFIED
this.mode = "CORNER"; //accepts 'CORNER' or 'CENTER'
this.updateTextSize = function () {
if (this.textScaled) {
for (let i = this.height; i > 0; i--) {
if (getTextBounds(this.text, this.textFont, i)[0] <= this.width
&& getTextBounds(this.text, this.textFont, i)[1] <= this.height) {
console.log("textbounds: " + getTextBounds(this.text, this.font, i));
console.log("boxsize: " + this.width + ", " + this.height);
this.textSize = i / 2;
break;
}
}
}
}
this.updateTextSize();
this.onHover = function () {
//This function is ran when the clickable is hovered but not
//pressed.
}
this.onOutside = function () {
//This function is ran when the clickable is NOT hovered.
}
this.onPress = function () {
//This function is ran when the clickable is pressed.
}
this.onRelease = function () {
//This function is ran when the cursor was pressed and then
//released inside the clickable. If it was pressed inside and
//then released outside this won't run.
}
this.locate = function (x, y) {
this.x = x;
this.y = y;
}
this.resize = function (w, h) {
this.width = w;
this.height = h;
this.updateTextSize();
}
this.drawImage = function(){
push();
imageMode(CENTER);
let centerX = this.x + this.width / 2;
let centerY = this.y + this.height / 2;
let imgWidth = this.width;
let imgHeight = this.height;
if(this.fitImage){
let imageAspect = this.image.width / this.image.height;
let buttonAspect = this.width / this.height;
if(imageAspect > buttonAspect){ // image is wider than button
imgWidth = this.width;
imgHeight = this.height * (buttonAspect / imageAspect);
}
else{
imgWidth = this.width * (imageAspect / buttonAspect);
imgHeight = this.height;
}
}
image(this.image, centerX, centerY, imgWidth * this.imageScale, imgHeight * this.imageScale);
if(this.tint && !this.noTint){
tint(this.tint)
} else {
noTint();
}
if(this.filter){
filter(this.filter);
}
pop();
}
this.draw = function () {
push();
fill(this.color);
stroke(this.stroke);
strokeWeight(this.strokeWeight);
// MODIFIED ////
let drawX = this.x;
let drawY = this.y;
if (this.mode === "CENTER") {
rectMode(CENTER);
drawX = this.x;
drawY = this.y;
} else {
rectMode(CORNER);
drawX = this.x;
drawY = this.y;
}
///
rect(drawX, drawY, this.width, this.height, this.cornerRadius);
fill(this.textColor);
noStroke();
if(this.image){
this.drawImage();
}
textAlign(CENTER, CENTER);
textSize(this.textSize);
textFont(this.textFont);
// MODIFIED ///
let textX = drawX;
let textY = drawY;
if (this.mode === "CENTER") {
textX = drawX;
textY = drawY;
} else {
textX = drawX + this.width / 2;
textY = drawY + this.height / 2;
}
text(this.text, textX, textY);
/////
// text(this.text, this.x + this.width / 2, this.y + this.height / 2);
// if (mouseX >= this.x && mouseY >= this.y
// && mouseX < this.x + this.width && mouseY < this.y + this.height) {
// cl_lastHovered = this;
// if (mouseIsPressed && !cl_mouseWasPressed)
// cl_lastClicked = this;
// }
// MODIFIED ///
let mouseOver = false;
if (this.mode === "CENTER") {
mouseOver = (
mouseX >= this.x - this.width / 2 &&
mouseX <= this.x + this.width / 2 &&
mouseY >= this.y - this.height / 2 &&
mouseY <= this.y + this.height / 2
);
} else {
mouseOver = (
mouseX >= this.x &&
mouseX <= this.x + this.width &&
mouseY >= this.y &&
mouseY <= this.y + this.height
);
}
if (mouseOver) {
cl_lastHovered = this;
if (mouseIsPressed && !cl_mouseWasPressed) {
cl_lastClicked = this;
}
}
/////
pop();
}
cl_clickables.push(this);
}