Two things. First of all, @GoToLoop, where can I download the “gotoloop.listener.CanvasResizeWatcher” library? I see the GitHub page for it all, but I don’t know how to download that as a library. I’m very curious to see what it does, and how it could help me with this predicament.
Second of all, I finished that fork I promised. The code is attached below. Whenever your mouse goes into/out of the canvas, the size is updated so that aspect ratio is preserved.
//Credit goes to Processing forum user Quark for the original code this was based off.
//https://discourse.processing.org/u/quark
float ratio=4.0/3; //record the height over width ratio
int widthLast=300, heightLast=400; //these record the dimensions every time the mouse enters/exits the canvas
int xLast, yLast; //these record the position of the top left of the canvas right before we resize the window
int xLFrame, yLFrame; //these record the position of the top left of the canvas in the previous frame
void settings() {
size(300,400); //for this example, we will go for a size of 300,400, correlating to a 3:4 aspect ratio
}
//A note to novice programmers reading this, you could just as well put size() in the setup function, so long as your dimensions are expressed as literals
void setup() {
surface.setResizable(true); //make the canvas resizable
xLFrame=xLast=get_sketch_location_x(); //initialize these values
yLFrame=yLast=get_sketch_location_y();
}
void draw() {
scale(width/300.0, height/400.0); //scale the canvas appropriately
background(255, 200, 0); //This is what quark originally had in the draw function. I modified it, though,
fill(0, 200, 0); //so you could write code without having to constantly reference the width &
rect(75,100,150,200); //height (assuming you wanted to draw more than just a rectangle). Of course, this
//has its drawbacks, especially if you plan on having consistent strokeWeight.
int x=get_sketch_location_x(), y=get_sketch_location_y(); //compute the canvas's position
if(x==xLFrame && y==yLFrame && widthLast==width && heightLast==height) { //if the position didn't change between frames, and the width & height aren't being changed
xLast=x; yLast=y; //record xLast & yLast
}
xLFrame=x; yLFrame=y; //set these values to the canvas's position at the end of the frame
}
void mouseEntered() {
updateDimensions(); //change dimensions every time the mouse enters the canvas
}
void mouseExited() {
updateDimensions(); //and every time it leaves the canvas
}
void updateDimensions() { //this code is run in the mouseEntered & mouseExited functions. It's the least buggy way I can maintain aspect ratio.
if(width!=widthLast || height!=heightLast) { //Check that the dimensions are different than they were last time this function ran
int x=get_sketch_location_x(), y=get_sketch_location_y(); //canvas's position
int minW=surface.MIN_WINDOW_WIDTH,
minH=surface.MIN_WINDOW_HEIGHT; //minimum window dimensions
float prefW, prefH; //preferred window dimensions
/////////////////////////COMPUTE PREFERRED DIMENSIONS////////////////////////////////////
if(width!=widthLast && height!=heightLast) { //if the user resized the window diagonally:
prefW=(width+height*ratio)/(sq(ratio)+1); prefH=prefW*ratio; //option 1: choose dimensions that minimize Pythagorean distance
//prefH=0.5*(width*ratio+height); prefW=prefH/ratio; //option 2: same as option 1, but stretched & skewed
//prefW=width; prefH=width*ratio; //option 3: preserve the width. This is how a lot of desktop card games maintain aspect ratio
//prefW=height/ratio; prefW=height; //option 4: same as option 3, but w/ the height
} //go with whatever option you like best.
else if(width!=widthLast) { prefW=width; prefH=width*ratio; } //user only changed the width
else { prefW=height/ratio; prefH=height; } //user only changed the height
/////////////////////////////////////SET DIMENSIONS/////////////////////////////////////////
if(prefW >=minW && prefH >=minH) { surface.setSize(round(prefW),round(prefH)); } //preferred dimensions aren't too small
else { //preferred dimensions are too small:
if(minW*ratio >= minH) { surface.setSize(minW, round(minW*ratio)); } //choose smallest possible dimensions that preserve aspect ratio
else { surface.setSize(round(minW/ratio), minH); } //this means either width = minW or height = minH
}
///////////////////////////////////SET LOCATION///////////////////////////////////
//here, we change the location so the corner/edge opposite to the one the mouse dragged stays put
int xPos=x, yPos=y; //xPos, yPos: where we want the canvas to be (init to current position)
if(x != xLast) { xPos=xLast+widthLast-width; } //x changed since resizing: edge/corner is on the left
if(y != yLast) { yPos=yLast+heightLast-height; } //y changed since resizing: edge/corner is on the top
if(x!=xPos || y!=yPos) { surface.setLocation(xPos,yPos); } //set location
/////////////////////////////////UPDATE////////////////////////////
widthLast=width; heightLast=height; //record the most recent values for the width and height
}
}
///////////////////////////POSITION FETCHING FUNCTIONS I DON'T UNDERSTAND EVEN SLIGHTLY/////////////////////////////////////////////////
//Credit goes to Processing forum user "Stanlepunk" for the following code.
//profile: https://discourse.processing.org/u/stanlepunk/
//original post: https://discourse.processing.org/t/getlocation-of-the-sketch/5763
//He also lists an "improved" version of the code, compatible with all renderers (e.g. P2D, P3D). I couldn't get it to work. The function "get_renderer()" seems not to exist.
int get_sketch_location_x() {
return getJFrame(getSurface()).getX();
}
int get_sketch_location_y() {
return getJFrame(getSurface()).getY();
}
static final javax.swing.JFrame getJFrame(final PSurface surface) {
return (javax.swing.JFrame) ( (processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
}
There are a couple bugs/exploits, and I might work to fix them some day…but it’d probably be like putting lipstick on a pig, if we’re being honest.
Known Bugs:
- Not compatible with P2D or P3D renderers.
- If you try resizing the window to be bigger than MAX_WINDOW_SIZE, things kinda just break. This should be easy to fix, but for some reason, I actually can’t seem to figure out the maximum window size.
- If you resize the window to the minimum size, the window will sometimes move a pixel away from where it was before. This bug persists anytime you setResizable(true), regardless of if you use my code. Thus, there’s no real way for me to fix it.
- While resizing the window, visual glitches occur frequently. Again, this happens regardless of if you use my code. It’s just a problem with either Processing or Windows OS.
- If you resize the window, then (without putting your mouse back in the canvas first) you move the window, then finally put your mouse back in the canvas, the window will move back to where it was before step 1. This is technically more of an exploit than a glitch, as the code is just looking at whatever corner/edge is opposite to the one you were dragging around, then places that corner/edge in the same location it was at the start. I thought this’d be easy to fix, but it’s actually kinda tricky, so I more or less gave up.