How can I zoom out properly within a EditorWindow

Hi,

As the title asks, I am wondering how I can zoom gui components out properly within a EditorWindow. My code is as follows:

Matrix4x4 before = GUI.matrix;
//Scale my gui matrix
GUI.matrix = Matrix4x4.Scale(new Vector3(zoomScale, zoomScale, zoomScale));
//Draw my zoomed GUI
DrawGUI();

//reset the matrix
GUI.matrix = before;

The problem I am getting is that the insides of the editorwindow is moving outside of its limits. alt text

An evil workaround-hack for custom windows would be applying a translation matrix before scaling and then revert the translation. That way you can move the vanishing point for scaling to a fix position within the window.

Matrix4x4 before = GUI.matrix;
//Scale my gui matrix
Matrix4x4 Translation = Matrix4x4.TRS(new Vector3(0,25,0),Quaternion.identity,Vector3.one);
Matrix4x4 Scale = Matrix4x4.Scale(new Vector3(zoomScale, zoomScale, zoomScale));
GUI.matrix = Translation*Scale*Translation.inverse;

//Draw my zoomed GUI
DrawGUI();

//reset the matrix
GUI.matrix = before;

edit

Here’s an example editorwindow:

using UnityEngine;
using UnityEditor;

public class ScaleTest : EditorWindow
{
    [MenuItem("Window/ScaleTest")]
    static void Init()
    {
        EditorWindow.GetWindow(typeof(ScaleTest));
    }

    float zoomScale = 1.0f;    
    Vector2 vanishingPoint = new Vector2(0,21);

    void OnGUI()
    {
        Matrix4x4 oldMatrix = GUI.matrix;

        //Scale my gui matrix
        Matrix4x4 Translation = Matrix4x4.TRS(vanishingPoint,Quaternion.identity,Vector3.one);
        Matrix4x4 Scale = Matrix4x4.Scale(new Vector3(zoomScale, zoomScale, 1.0f));
        GUI.matrix = Translation*Scale*Translation.inverse;

        // Draw the GUI
        GUI.Button(new Rect(0, 0 , position.width*1.5f, 30),"Foo");
        GUI.Button(new Rect(0, 35, 50,                  30),"Bar");
        EditorGUI.FloatField(new Rect(0, 70, 50,30),0.0f);

        //reset the matrix
        GUI.matrix = oldMatrix;

        // Just for testing (unscaled controls at the bottom)
        GUILayout.FlexibleSpace();
        vanishingPoint = EditorGUILayout.Vector2Field("vanishing point",vanishingPoint);
        zoomScale = EditorGUILayout.Slider("zoom",zoomScale,1.0f/25.0f,2.0f);
    }

}

But as i said already the EditorGUI stuff is not designed to be scaled. You will get a strange behaviour. If you want to scale it down to have more space to draw, that won't work because GUI.matrix also affects the clipping rect of the window. If you scale down the GUI, the drawable area will also shrink.

Here's an overview how it works:

scaling


second edit

I just found a built in function that do the same but even better :D. The EditorGUI problem will be the same (clip rect and mouse cursor) but you can specify the vanishing point in client coordinates like you do with all the GUI stuff.

That will scale around the "client coordinate" [0,0].

`GUIUtility.ScaleAroundPivot(Vector2.one * zoomScale,Vector2.zero);`

I wrote a blog post on this topic recently that solves (or “hacks around”, if you will) the problem of the clipping rect being incorrect after scaling via GUI.matrix.
Check it out here: http://martinecker.com/martincodes/unity-editor-window-zooming/

Here’s a version of Bunny’s that uses mouse wheel instead of slider to zoom. I’m not sure about the ‘e.Use()’ at the end. I’m also not certain what’s the best value for the ‘vanishing point’

using UnityEngine;
using UnityEditor;

public class ScaleTest : EditorWindow
{
    [MenuItem("Window/ScaleTest")]
    static void Init()
    {
        EditorWindow.GetWindow(typeof(ScaleTest));
    }

    float zoomScale = 1.0f;

    void OnGUI()
    {
        Matrix4x4 oldMatrix = GUI.matrix;

        //Scale my gui matrix
        Vector2 vanishingPoint = new Vector2(0, 20);
        Matrix4x4 Translation = Matrix4x4.TRS(vanishingPoint, Quaternion.identity, Vector3.one);
        Matrix4x4 Scale = Matrix4x4.Scale(new Vector3(zoomScale, zoomScale, 1.0f));
        GUI.matrix = Translation * Scale * Translation.inverse;

        // Draw the GUI
        GUI.Button(new Rect(0, 0, position.width * 1.5f, 30), "Foo");
        GUI.Button(new Rect(0, 35, 50, 30), "Bar");
        EditorGUI.FloatField(new Rect(0, 70, 50, 30), 0.0f);

        //reset the matrix
        GUI.matrix = oldMatrix;

        var e = Event.current;
        if (e.type == EventType.ScrollWheel)
        {
            var zoomDelta = 0.1f;
            zoomDelta = e.delta.y < 0 ? zoomDelta : -zoomDelta;
            zoomScale += zoomDelta;
            zoomScale = Mathf.Clamp(zoomScale, 0.25f, 1.25f);
            e.Use();
        }
    }
}

I am trying to get this to work and also to be able to use scrolling. I had to treat scale>=1 differently then scale<1. This is not perfect but if you can use it and manage to make it better, please post your code!

public static Vector2 scrollPosition = new Vector2(0,0);
Rect virtualWindow = new Rect (0, 0, 1000, 1000);
float maxX=0;
float maxY=0;
private static Vector2 pivotPoint;
private static Vector2 scale_ = new Vector2(scale, scale);

void OnGUI()
{
	
	maxX=0;
	maxY=0;
	scale = EditorGUI.Slider(new Rect(position.width/2-100,50,150,20),scale,.5f, 2);
	drawScrollable(scale);
    }

private void drawScrollable(float scale)
{
	
	pivotPoint = new Vector2(position.width / 2, position.height / 2);
	scale_.x=scale;
	scale_.y=scale;
	
	
	
	
	Rect clippedArea =  virtualWindow;//.ScaleSizeBy(scale, Vector2.zero);
	
	
	float posAdjX = 0;
	float posAdjY = 0;
	float leftAdjX = 0;
	float leftAdjY = 0;
	Rect scaledVirtualWindow = virtualWindow;
	if(scale>=1f)
		{
			clippedArea.y += 24*scale;
			pivotPoint.x+=scrollPosition.x/2f;
			pivotPoint.y+=scrollPosition.y/2f;
			scaledVirtualWindow = virtualWindow.ScaleSizeBy(scale,pivotPoint);
			
			
		}
	else
		{
			clippedArea.y += 24/scale;
			pivotPoint.x+=scrollPosition.x;
			pivotPoint.y+=scrollPosition.y;
			
			posAdjX=position.width*(scale+1f)-(position.width*scale);
			posAdjY=position.height*(scale+1f)-(position.height*scale);
			
			leftAdjX = (position.width-(posAdjX/scale))/4f;
			leftAdjY = (position.height-(posAdjY/scale))/4f;			
		}
			
	GUI.Label(new Rect(position.width/2-150,70,550,20),
		" svw.left="+scaledVirtualWindow.left+" svw.width="+scaledVirtualWindow.width);
	GUI.Label(new Rect(position.width/2-150,100,550,20),
		" clipped.left="+clippedArea.left+" clipped.width="+clippedArea.width+"  adjustX="+leftAdjX);
	
	
	
	GUI.EndGroup();
	//if(scrollPosition.y<0)scrollPosition.y=0;
	scrollPosition = 
	GUI.BeginScrollView ( new Rect (leftAdjX,leftAdjY,position.width+posAdjX, position.height+posAdjY), scrollPosition, scaledVirtualWindow);
	if(scrollPosition.y<0)scrollPosition.y=0;
	if(scrollPosition.x<0)scrollPosition.x=0;
	Matrix4x4 oldMatrix = GUI.matrix;
		GUIUtility.ScaleAroundPivot(scale_, pivotPoint);
		
			GUI.BeginGroup(clippedArea);

				drawDialogNodes();//my method to draw nodes
				drawLinks();	//my method to draw the links
				
			GUI.EndGroup();
		GUI.matrix = oldMatrix;
	
	GUI.EndScrollView();

	GUI.BeginGroup(new Rect(.0f, 24, Screen.width, Screen.height-24));

}