Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Is there a resize equivalent to GUI.DragWindow?

Discussion in 'Immediate Mode GUI (IMGUI)' started by SWGraham, Apr 15, 2008.

  1. SWGraham

    SWGraham

    Joined:
    Mar 10, 2008
    Posts:
    49
    I love my new draggable window. But I don't see an easy function for resizing. I could change the width and height parameters of the window position Rect by myself, but what kind of widget would be appropriate for making the little drag target square in the bottom right?
     
    ModLunar likes this.
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yeah, there's no built-in function for resizing. The file requester window resize widget in this was done using Rect.Contains. The "widget" is just part of the window border, not actually a separate thing, aside from being defined as a 25-pixel square Rect. Then there's a little code:

    Code (csharp):
    1. var mousePos = Input.mousePosition;
    2. mousePos.y = Screen.height - mousePos.y;    // Convert to GUI coords
    3. windowHandle = Rect(fileWindow.x+fileWindow.width-25, fileWindow.y+fileWindow.height-25, 25, 25)
    4.  
    5. // If clicked on window resize widget
    6. if (Input.GetMouseButtonDown(0)  windowHandle.Contains(mousePos)) {
    7.     handleClicked = true;
    8.     clickedPosition = mousePos;
    9.     originalWindow = fileWindow;
    10. }
    11.  
    12. if (handleClicked) {
    13.     // Resize window by dragging
    14.     if (Input.GetMouseButton(0)) {
    15.         fileWindow.width = Mathf.Clamp(originalWindow.width + (mousePos.x - clickedPosition.x), minWindowWidth, maxWindowWidth);
    16.         fileWindow.height = Mathf.Clamp(originalWindow.height + (mousePos.y - clickedPosition.y), minWindowHeight, maxWindowHeight);
    17.     }
    18.     // Finish resizing window
    19.     if (Input.GetMouseButtonUp(0)) {
    20.         handleClicked = false;
    21.     }
    22. }
    In order for that to work successfully, the elements in the window have to be coded to draw relatively, of course, since the window can be any size at any time. Maybe there's a better way, but that's how I did it anyway.

    --Eric
     
  3. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    FWIW, This whole code can be done quite a bit nicer if you don't use Input.Whatever, but instead use Event.current to get to the user's mouse position. Something along the lines shown here: http://forum.unity3d.com/viewtopic.php?t=9677
     
  4. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    I've got some code that does both drag and resize. Unfortunately, in Unity 2.0.2 this doesn't work on the Mac Web player (it does work on all other players including the Windows Web player). Bug report filed a while back... When 2.0.3 comes out, and that's fixed (or if I find a workaround), I'd share that little piece of code...
     
  5. yoyo

    yoyo

    Joined:
    Apr 16, 2010
    Posts:
    112
    Four years later and still no GUI.ResizeWindow, sigh.

    I hacked this together using another draggable window for the drag target square, whose position is then used to update the window being resized (on Layout event). Not ideal, especially because relative-position child windows aren't supported, but mostly it works.
     
  6. SinisterMephisto

    SinisterMephisto

    Joined:
    Feb 18, 2011
    Posts:
    179
    I cant believe this. Unity has this build in its editor. Here is my attempt.
    It is far from smooth. Rather choppy but works

    Code (csharp):
    1.  
    2. void HorizResizer(ref Rect r, bool right = true, float detectionRange = 8f)
    3.     {
    4.         detectionRange *= 0.5f;
    5.         Rect resizer = r;
    6.  
    7.         if (right)
    8.         {
    9.             resizer.xMin = resizer.xMax - 4; //4 pixels wide
    10.             resizer.xMax += 4;
    11.         }
    12.         else
    13.         {
    14.             resizer.xMax = resizer.xMin + detectionRange;
    15.             resizer.xMin -= detectionRange;
    16.         }
    17.         Event current = Event.current;
    18.         EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeHorizontal);
    19.         //Need a way to remove this Contain check since we already know where the mouse is
    20.         if (resizer.Contains(mousePos))
    21.         {
    22.             if (current.type == EventType.MouseDrag)
    23.             {
    24.                 if (current.button == 0) //lmouse
    25.                 {
    26.                     if (right)
    27.                     { r.xMax += current.delta.x; }
    28.                     else
    29.                     { r.xMin += current.delta.x; }
    30.                 }
    31.             }
    32.         }
    33.     }
    34.  
    35.     void OnGUI()
    36.     {
    37.         BeginWindows();
    38.         //Resize 1 or both ends
    39.         HorizResizer(ref windowRect); //right
    40.         HorizResizer(ref windowRect,false); //left
    41.         windowRect = GUI.Window(0, windowRect, DoMyWindow, "My Window");
    42.         EndWindows();  
    43.     }
    44.  
    45.  
     
    Last edited: May 16, 2013
  7. SinisterMephisto

    SinisterMephisto

    Joined:
    Feb 18, 2011
    Posts:
    179
    The choppiness comes from doing the resize in the OnGUI.
    Its frame rate varies from 2-6fps cannot keep up with mouse.

    Code (csharp):
    1. if (current.button == 0) //lmouse
    2. {
    3.     if (right)
    4.     { windowRect.xMax += current.delta.x; }
    5.     else
    6.     { windowRect.xMin += current.delta.x; }
    7.     //slightly reduced lag
    8.     Repaint();
    9. }
    10.  
    11.  
    Don't scale the delta. It looks odd
    Increase detection range to 16


    Unity please make
    Code (csharp):
    1. EditorGUIUtility.AddCursorRect
    return a bool
    Based on if the cursor is within the supplied rectangle
     
    Last edited: May 16, 2013
  8. SinisterMephisto

    SinisterMephisto

    Joined:
    Feb 18, 2011
    Posts:
    179
    Fixed the lag.
    Code (csharp):
    1.  
    2.  //Update your min/max with
    3.  rect.xMin = current.mousePosition.x + current.delta.x;
    4.  rect.xMax = current.mousePosition.x + current.delta.x;
    5.  
     
  9. Charl Marais

    Charl Marais

    Joined:
    Oct 21, 2013
    Posts:
    12
    Thank you SinisterMephist

    This script came in handy when I was working on resizable GUI area's. :) I had to adopt it a bit due to my implimentation but it works reliably.
    I modified the code by:
    1. condensing the IF statments into a single check
    2. removing the resizer.contains(mousePos) check and replacing with the below check (much faster):

    Code (csharp):
    1. current.mousePosition.x > resizer.xMin  current.mousePosition.x < resizer.xMax
    3. Added _mbStillHeldLeft and _mbStillHeldRight booleans to bypass all checks as long as the mousbutton hasnt been released yet.

    You can see the code below:

    Code (csharp):
    1.  
    2. private bool _mbStillHeldLeft = false;
    3. private bool _mbStillHeldRight = false;
    4.    
    5. void HorizResizer(Rect r, bool right = true, float detectionRange = 8f) {
    6.     detectionRange *= 0.5f;
    7.     Rect resizer = r;
    8.    
    9.     if (right) {
    10.       resizer.xMin = resizer.xMax - detectionRange; //4 pixels wide
    11.       resizer.xMax += detectionRange;
    12.     } else {
    13.       resizer.xMax = resizer.xMin + detectionRange;
    14.       resizer.xMin -= detectionRange;
    15.     }
    16.            
    17.     Event current = Event.current;
    18.     EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeHorizontal);
    19.  
    20.     if (current.type == EventType.MouseUp) {
    21.     _mbStillHeldLeft = false;
    22.     _mbStillHeldRight = false;
    23.     }
    24.        
    25.     if (current.mousePosition.x > resizer.xMin  current.mousePosition.x < resizer.xMax  current.type == EventType.MouseDrag  current.button == 0 || _mbStillHeldLeft || _mbStillHeldRight) {
    26.     if (right  !_mbStillHeldLeft) {
    27.         LeftPanelWidth = Mathf.RoundToInt(current.mousePosition.x + current.delta.x);
    28.         Repaint();
    29.         _mbStillHeldRight = true;
    30.     } else if (!right  !_mbStillHeldRight){
    31.         RightPanelWidth = Mathf.RoundToInt(mapManagerWindow.position.width - (current.mousePosition.x + current.delta.x));
    32.         Repaint();
    33.         _mbStillHeldLeft = true;
    34.     }
    35.     }
    36. }
    37.  
    Of course I needed to convert the result to an Int and feed it back into my frame constructor. I suppose I could remove the ref from my Rect as well in the implimentation. Anyways you just need to substitute the below in the above script.

    Code (csharp):
    1.  LeftPanelWidth = Mathf.RoundToInt(current.mousePosition.x + current.delta.x);
    with :

    Code (csharp):
    1.  r.xMin = current.mousePosition.x + current.delta.x;
    and

    Code (csharp):
    1.  RightPanelWidth = Mathf.RoundToInt(mapManagerWindow.position.width - (current.mousePosition.x + current.delta.x));
    with :

    Code (csharp):
    1.  r.xMax = current.mousePosition.x + current.delta.x;
    Hopefully this is helpful to someone else.
     
    Last edited: Jan 28, 2014
  10. AntFitch

    AntFitch

    Joined:
    Jan 31, 2012
    Posts:
    243
    I needed this! Since it's been a while since this thread has been updated and it looks like some symbols were lost in the latest version of the code above, I've re-posted it with a few changes.

    Notes: symbols re-added, renamed a few fields, cut a few things out, got rid of ref.

    Code (CSharp):
    1.  
    2. Rect windowMenu;
    3. bool draggingLeft = false;
    4. bool draggingRight = false;
    5.  
    6. void OnEnable()
    7. {
    8.     windowMenu.width = 330;
    9. }
    10.  
    11. void OnGUI()
    12.     {
    13.         windowMenu = new Rect(0, 0, windowMenu.width, Screen.height - 40);
    14.  
    15.         BeginWindows();
    16.         windowMenu = HorizResizer(windowMenu); //right
    17.         windowMenu = HorizResizer(windowMenu,false); //left
    18.         windowMenu = GUI.Window(0, windowMenu, DoMyWindow, "My Window");
    19.         EndWindows();
    20.     }
    21.  
    22. private Rect HorizResizer(Rect window, bool right = true, float detectionRange = 8f)
    23. {        
    24.     detectionRange *= 0.5f;
    25.     Rect resizer = window;
    26.  
    27.     if (right)
    28.     {
    29.         resizer.xMin = resizer.xMax - detectionRange;
    30.         resizer.xMax += detectionRange;
    31.     }
    32.     else
    33.     {
    34.         resizer.xMax = resizer.xMin + detectionRange;
    35.         resizer.xMin -= detectionRange;
    36.     }
    37.  
    38.     Event current = Event.current;
    39.     EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeHorizontal);
    40.  
    41.     // if mouse is no longer dragging, stop tracking direction of drag
    42.     if (current.type == EventType.MouseUp)
    43.     {
    44.         draggingLeft = false;
    45.         draggingRight = false;
    46.     }
    47.  
    48.     // resize window if mouse is being dragged within resizor bounds
    49.     if (current.mousePosition.x > resizer.xMin &&
    50.         current.mousePosition.x < resizer.xMax &&
    51.         current.type == EventType.MouseDrag &&
    52.         current.button == 0 ||
    53.         draggingLeft ||
    54.         draggingRight)
    55.     {
    56.         if (right == !draggingLeft)
    57.         {
    58.             window.width = current.mousePosition.x + current.delta.x;
    59.             Repaint();
    60.             draggingRight = true;
    61.         }
    62.         else if (!right == !draggingRight)
    63.         {
    64.             window.width = window.width - (current.mousePosition.x + current.delta.x);
    65.             Repaint();
    66.             draggingLeft = true;
    67.         }
    68.  
    69.     }
    70.  
    71.     return window;
    72. }
    73.  
     
    Last edited: Nov 18, 2016
    ModLunar and vectorized-runner like this.
  11. SnowboarderX

    SnowboarderX

    Joined:
    Jun 20, 2015
    Posts:
    5

    Hey all, I took this code and added some functionality to it. Now you can resize in the x and y directions. Also, I added minimum width and height for a little more polish.

    Code (csharp):
    1.  
    2. private bool draggingLeft = false;
    3. private bool draggingRight = false;
    4. private bool draggingUp = false;
    5. private bool draggingDown = false;
    6. private bool canDrag = false;
    7.  
    8. private Rect Resizer(Rect window, int dir = 0, float detectionRange = 16f)
    9.     {
    10.         detectionRange *= .5f;
    11.         Rect resizer = window;
    12.  
    13.         if (dir == 0)
    14.         {
    15.             // left
    16.             resizer.xMax = resizer.xMin + detectionRange;
    17.             resizer.xMin -= detectionRange;
    18.         }
    19.         else if (dir == 1)
    20.         {
    21.             // right
    22.             resizer.xMin = resizer.xMax - detectionRange;
    23.             resizer.xMax += detectionRange;
    24.         }
    25.         else if (dir == 2)
    26.         {
    27.             // up
    28.             resizer.yMax = resizer.yMin + detectionRange;
    29.             resizer.yMin -= detectionRange;
    30.         }
    31.         else
    32.         {
    33.             // down
    34.             resizer.yMin = resizer.yMax - detectionRange;
    35.             resizer.yMax += detectionRange;
    36.         }
    37.  
    38.         //Debug.Log("Dir: " + dir + "\n(" + resizer.xMin + ", " + resizer.xMax + ")\n(" + resizer.yMin + ", " + resizer.yMax + ")");
    39.  
    40.         Event current = Event.current;
    41.         if (dir == 0 || dir == 1)
    42.         {
    43.             EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeHorizontal);
    44.         }
    45.         else
    46.         {
    47.             EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeVertical);
    48.         }
    49.  
    50.         if (current.type == EventType.MouseUp)
    51.         {
    52.             draggingLeft = false;
    53.             draggingRight = false;
    54.             draggingUp = false;
    55.             draggingDown = false;
    56.             canDrag = false;
    57.         }
    58.  
    59.         bool inXRange = current.mousePosition.x > resizer.xMin && current.mousePosition.x < resizer.xMax;
    60.         bool inYRange = current.mousePosition.y > resizer.yMin && current.mousePosition.y < resizer.yMax;
    61.  
    62.  
    63.  
    64.         if (current.type == EventType.MouseDown &&
    65.             (inXRange && inYRange))
    66.         {
    67.             canDrag = true;
    68.         }
    69.  
    70.         if (canDrag)
    71.         {
    72.             if (inXRange && inYRange &&
    73.                 current.type == EventType.MouseDrag &&
    74.                 current.button == 0 ||
    75.                 draggingLeft ||
    76.                 draggingRight)
    77.             {
    78.                 if ((dir == 1) && !(draggingRight || draggingUp || draggingDown))
    79.                 {
    80.                     window.width += current.delta.x / 2f;
    81.                     window.width = Mathf.Max(100f, window.width);
    82.                     Repaint();
    83.                     draggingLeft = true;
    84.  
    85.                 }
    86.  
    87.                 if ((dir == 0) && !(draggingLeft || draggingUp || draggingDown))
    88.                 {
    89.                     window.x += current.delta.x / 2f;
    90.                     window.width -= current.delta.x / 2f;
    91.                     window.width = Mathf.Max(100f, window.width);
    92.                     Repaint();
    93.                     draggingRight = true;
    94.                 }
    95.             }
    96.  
    97.             if (inXRange && inYRange &&
    98.                 current.type == EventType.MouseDrag &&
    99.                 current.button == 0 ||
    100.                 draggingUp ||
    101.                 draggingDown)
    102.             {
    103.                 if ((dir == 2) && !(draggingDown || draggingLeft || draggingRight))
    104.                 {
    105.                     window.y += current.delta.y / 2f;
    106.                     window.height -= current.delta.y / 2f;
    107.                     window.height = Mathf.Max(50f, window.height);
    108.                     Repaint();
    109.                     draggingUp = true;
    110.                 }
    111.  
    112.                 if ((dir == 3) && !(draggingUp || draggingLeft || draggingRight))
    113.                 {
    114.                     window.height += current.delta.y / 2f;
    115.                     window.height = Mathf.Max(50f, window.height);
    116.                     Repaint();
    117.                     draggingDown = true;
    118.                 }
    119.             }
    120.         }
    121.  
    122.         return window;
    123.     }
    124.  
    125. void OnGUI() {
    126.     BeginWindows();
    127.     for(int i = 0; i<windows.Count; i++) {
    128.         window = windows[i];
    129.         for(int dir = 0; dir<4; dir++)
    130.             window = Resizer(window, dir) // one function call per cardinal direction
    131.         Rect new_window = GUI.Window(i, window, WindowDrawingFunction, "My Window");
    132.      }
    133.      EndWindows();
    134. }
    135.  
    136. void WindowDrawingFunction() {
    137.      bool button = GUILayout.Toggle(button, "Example window");
    138. }
    139.  
    140.  
    Also showed how you can use this for multiple windows. Only issue I'm having now is for some reason any resizing of one window affects all others. I've been scratching my head at this for over a day now so if anyone knows why, let me know. I think it may just come down to how Unity handles windows.
     
  12. SnowboarderX

    SnowboarderX

    Joined:
    Jun 20, 2015
    Posts:
    5

    Ok, nevermind, I figured it out and it was my fault. I didn't consider that every window should have its own booleans for keeping track of being dragged in each direction since the proximity check to the handles is overrided if they are true.

    Here is my solution:

    1. Create a new wrapper class around your Rect's for your windows

    Code (csharp):
    1.  
    2. public class NodeWindow
    3. {
    4.     public Rect rect;
    5.     public string title;
    6.  
    7.     public bool draggingLeft = false;
    8.     public bool draggingRight = false;
    9.     public bool draggingUp = false;
    10.     public bool draggingDown = false;
    11.     public bool canDrag = false;
    12.  
    13.     public NodeWindow(string title, Rect rect)
    14.     {
    15.         this.title = title;
    16.         this.rect = rect;
    17.     }
    18.  
    19.    
    20.  
    21. }
    22.  
    2. This is the new correct Resizer method.

    Code (csharp):
    1.  
    2. private Rect Resizer(NodeWindow nodeWindow, int dir = 0, float detectionRange = 16f)
    3.     {
    4.         Rect window = nodeWindow.rect;
    5.         detectionRange *= .5f;
    6.         Rect resizer = window;
    7.  
    8.         if (dir == 0)
    9.         {
    10.             // left
    11.             resizer.xMax = resizer.xMin + detectionRange;
    12.             resizer.xMin -= detectionRange;
    13.         }
    14.         else if (dir == 1)
    15.         {
    16.             // right
    17.             resizer.xMin = resizer.xMax - detectionRange;
    18.             resizer.xMax += detectionRange;
    19.         }
    20.         else if (dir == 2)
    21.         {
    22.             // up
    23.             resizer.yMax = resizer.yMin + detectionRange;
    24.             resizer.yMin -= detectionRange;
    25.         }
    26.         else
    27.         {
    28.             // down
    29.             resizer.yMin = resizer.yMax - detectionRange;
    30.             resizer.yMax += detectionRange;
    31.         }
    32.  
    33.         //Debug.Log("Dir: " + dir + "\n(" + resizer.xMin + ", " + resizer.xMax + ")\n(" + resizer.yMin + ", " + resizer.yMax + ")");
    34.        
    35.         Event current = Event.current;
    36.         if (dir == 0 || dir == 1)
    37.         {
    38.             EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeHorizontal);
    39.         }
    40.         else
    41.         {
    42.             EditorGUIUtility.AddCursorRect(resizer, MouseCursor.ResizeVertical);
    43.         }
    44.  
    45.         if (current.type == EventType.MouseUp)
    46.         {
    47.             nodeWindow.draggingLeft = false;
    48.             nodeWindow.draggingRight = false;
    49.             nodeWindow.draggingUp = false;
    50.             nodeWindow.draggingDown = false;
    51.             nodeWindow.canDrag = false;
    52.         }
    53.  
    54.         bool inXRange = current.mousePosition.x > resizer.xMin && current.mousePosition.x < resizer.xMax;
    55.         bool inYRange = current.mousePosition.y > resizer.yMin && current.mousePosition.y < resizer.yMax;
    56.  
    57.  
    58.  
    59.         if (current.type == EventType.MouseDown &&
    60.             (inXRange && inYRange))
    61.         {
    62.             nodeWindow.canDrag = true;
    63.         }
    64.  
    65.         if (nodeWindow.canDrag)
    66.         {
    67.             if (inXRange && inYRange &&
    68.                 current.type == EventType.MouseDrag &&
    69.                 current.button == 0 ||
    70.                 nodeWindow.draggingLeft ||
    71.                 nodeWindow.draggingRight)
    72.             {
    73.                 if ((dir == 1) && !(nodeWindow.draggingRight || nodeWindow.draggingUp || nodeWindow.draggingDown))
    74.                 {
    75.                     window.width += current.delta.x / 2f;
    76.                     window.width = Mathf.Max(100f, window.width);
    77.                     Repaint();
    78.                     nodeWindow.draggingLeft = true;
    79.  
    80.                 }
    81.  
    82.                 if ((dir == 0) && !(nodeWindow.draggingLeft || nodeWindow.draggingUp || nodeWindow.draggingDown))
    83.                 {
    84.                     window.x += current.delta.x / 2f;
    85.                     window.width -= current.delta.x / 2f;
    86.                     window.width = Mathf.Max(100f, window.width);
    87.                     Repaint();
    88.                     nodeWindow.draggingRight = true;
    89.                 }
    90.             }
    91.  
    92.             if (inXRange && inYRange &&
    93.                 current.type == EventType.MouseDrag &&
    94.                 current.button == 0 ||
    95.                 nodeWindow.draggingUp ||
    96.                 nodeWindow.draggingDown)
    97.             {
    98.                 if ((dir == 2) && !(nodeWindow.draggingDown || nodeWindow.draggingLeft || nodeWindow.draggingRight))
    99.                 {
    100.                     window.y += current.delta.y / 2f;
    101.                     window.height -= current.delta.y / 2f;
    102.                     window.height = Mathf.Max(50f, window.height);
    103.                     Repaint();
    104.                     nodeWindow.draggingUp = true;
    105.                 }
    106.  
    107.                 if ((dir == 3) && !(nodeWindow.draggingUp || nodeWindow.draggingLeft || nodeWindow.draggingRight))
    108.                 {
    109.                     window.height += current.delta.y / 2f;
    110.                     window.height = Mathf.Max(50f, window.height);
    111.                     Repaint();
    112.                     nodeWindow.draggingDown = true;
    113.                 }
    114.             }
    115.         }
    116.  
    117.         return window;
    118.     }
    119.  
    Then this is what your OnGUI() should look like:

    Code (csharp):
    1.  
    2. void OnGUI()
    3.     {
    4.        
    5.         BeginWindows();
    6.         for (int i = 0; i < windows.Count; i++)
    7.         {
    8.             NodeWindow window = windows[i].window;
    9.          
    10.  
    11.             for (int dir = 0; dir < 4; dir++)
    12.                 window.rect = Resizer(window, dir, 16);
    13.  
    14.             Rect temp = GUILayout.Window(i, window.rect, DrawNodeWindow, activeTree.nodes[i].window.title);
    15.  
    16.  
    17.             // then update node Rect to new temp Rect.
    18.             windows[i].window.rect = temp;
    19.  
    20.         }
    21.         EndWindows();
    22.  
    23.     }
    24.  
     
    lilacsky824 likes this.