Implemented new collisions check algorithm when resizing, it seems working well on...
authorterencehill <piuntn@gmail.com>
Thu, 17 Jun 2010 00:22:40 +0000 (02:22 +0200)
committerterencehill <piuntn@gmail.com>
Thu, 17 Jun 2010 00:22:40 +0000 (02:22 +0200)
Modified the panel aspect ratio handling too, it was causing troubles.

Added a temporary debug mode hud_configure_checkcollisions_debug only to highlight bad behavior during the execution, there could be minor bugs to fix.

qcsrc/client/hud.qc

index 4cc3fa6..3ef20f6 100644 (file)
@@ -682,8 +682,6 @@ vector HUD_Panel_GetMinSize(float id)
                        mySize_y = 0.25; // 0.25 * width, trial and error...
                        break;
        }
-       if(!mySize_x && mySize_y)
-               mySize_x = 1/mySize_y;
        return mySize;
 }
 
@@ -1038,135 +1036,114 @@ void HUD_Panel_SetPos(float id, vector pos)
        cvar_set(strcat("hud_", HUD_Panel_GetName(id), "_pos"), s);
 }
 
-float HUD_Panel_CheckValidity_of_ResizeSuggestion(float id, vector mySize)
-{
-       vector oldSize;
-       oldSize = mySize;
-
-       // copy pasta from SetPosSize:
-       // minimum panel size cap
-       mySize_x = max(0.025 * vid_conwidth, mySize_x);
-       mySize_y = max(0.025 * vid_conheight, mySize_y);
-
-       if(id == 12) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
-       {
-               mySize_x = max(17 * cvar("con_chatsize"), mySize_x);
-               mySize_y = max(2 * cvar("con_chatsize") + 2 * HUD_Panel_GetPadding(id), mySize_y);
-       }
-
-       // cap against panel's own limits
-       vector minSize;
-       minSize = HUD_Panel_GetMinSize(id); // mySize_x at least minSize_x * mySize_y, and vice versa
-
-       mySize_x = max(minSize_x * mySize_y, mySize_x);
-       mySize_y = max(minSize_y * mySize_x, mySize_y);
-
-       if(mySize == oldSize)
-               return 1;
-       else
-               return 0;
-}
-
 // check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
-vector HUD_Panel_CheckResize(float id, vector myPos, vector mySize, vector resizeorigin)
-{
+vector HUD_Panel_CheckResize(float id, vector mySize, vector resizeorigin, float ratio) {
        float i;
 
+       float targBorder;
        vector targPos;
        vector targSize;
-       vector myCenter;
-       vector targCenter;
-       myCenter = '0 0 0'; // shut up fteqcc, there IS a reference
-       targCenter = '0 0 0'; // shut up fteqcc, there IS a reference
+       vector targEndPos;
+       vector dist;
 
        for (i = 0; i < HUD_PANEL_NUM; ++i) {
                if(i == id || !HUD_Panel_CheckActive(i))
                        continue;
 
-               targPos = HUD_Panel_GetPos(i) - '1 1 0' * HUD_Panel_GetBorder(id);
-               targSize = HUD_Panel_GetSize(i) + '2 2 0' * HUD_Panel_GetBorder(id);
-
-               if(myPos_y + mySize_y < targPos_y)
-                       continue;
-               if(myPos_y > targPos_y + targSize_y)
-                       continue;
-
-               if(myPos_x + mySize_x < targPos_x)
-                       continue;
-               if(myPos_x > targPos_x + targSize_x)
-                       continue;
+               targBorder = HUD_Panel_GetBorder(i);
+               targPos = HUD_Panel_GetPos(i) - '1 1 0' * targBorder;
+               targSize = HUD_Panel_GetSize(i) + '2 2 0' * targBorder;
+               targEndPos = targPos + targSize;
 
-               // OK, there IS a collision.
-               //
-
-               // Now check some special cases
-               // If the resizeorigin is too close to the target panel on either axis, we do not want to perform any collision avoidance on that axis
-               float Check_X, Check_Y;
-               Check_X = Check_Y = 1;
-               // check upper/left edges of targ panel
-               if(fabs(targPos_x - resizeorigin_x) < 0.025 * vid_conwidth)
-                       Check_X = 0;
-               if(fabs(targPos_y - resizeorigin_y) < 0.025 * vid_conheight)
-                       Check_Y = 0;
-               // check lower/right edges of targ panel
-               if(fabs(resizeorigin_x - (targPos_x + targSize_x)) < 0.025 * vid_conwidth)
-                       Check_X = 0;
-               if(fabs(resizeorigin_y - (targPos_y + targSize_y)) < 0.025 * vid_conheight)
-                       Check_Y = 0;
-
-               myCenter_x = myPos_x + 0.5 * mySize_x;
-               myCenter_y = myPos_y + 0.5 * mySize_y;
-
-               targCenter_x = targPos_x + 0.5 * targSize_x;
-               targCenter_y = targPos_y + 0.5 * targSize_y;
-
-               if(myCenter_x < targCenter_x && myCenter_y < targCenter_y) // top left (of target panel)
+               if (resizeCorner == 1)
                {
-                       //if(!HUD_Panel_CheckValidity_of_ResizeSuggestion(id, eX * (targPos_x - myPos_x) + eY * (targPos_y - resizeorigin_y)))
-                       //      continue;
+                       // check if this panel is on our way
+                       if (resizeorigin_x < targPos_x)
+                               continue;
+                       if (resizeorigin_y < targPos_y)
+                               continue;
+                       if (targEndPos_x < resizeorigin_x - mySize_x)
+                               continue;
+                       if (targEndPos_y < resizeorigin_y - mySize_y)
+                               continue;
 
-                       if(myPos_x + mySize_x - targPos_x < myPos_y + mySize_y - targPos_y && Check_X) // push it to the side
-                               mySize_x = targPos_x - myPos_x;
-                       else if(Check_Y) // push it upwards
-                               mySize_y = targPos_y - resizeorigin_y;
+                       // there is a collision:
+                       // detect which side of the panel we are facing is actually limiting the resizing
+                       // (which side the resize direction finds for first) and reduce the size up to there
+                       //
+                       // dist is the distance between resizeorigin and the "analogous" point of the panel
+                       // in this case resizeorigin (bottom-right point) and the bottom-right point of the panel
+                       dist_x = resizeorigin_x - targEndPos_x;
+                       dist_y = resizeorigin_y - targEndPos_y;
+                       if (dist_y < 0 || dist_x / dist_y > ratio)
+                               mySize_x = min(mySize_x, dist_x);
+                       else
+                               mySize_y = min(mySize_y, dist_y);
                }
-               else if(myCenter_x > targCenter_x && myCenter_y < targCenter_y) // top right
+               else if (resizeCorner == 2)
                {
-                       //if(!HUD_Panel_CheckValidity_of_ResizeSuggestion(id, eX * (resizeorigin_x - (targPos_x + targSize_x)) + eY * (targPos_y - resizeorigin_y)))
-                       //      continue;
+                       if (resizeorigin_x > targEndPos_x)
+                               continue;
+                       if (resizeorigin_y < targPos_y)
+                               continue;
+                       if (targPos_x > resizeorigin_x + mySize_x)
+                               continue;
+                       if (targEndPos_y < resizeorigin_y - mySize_y)
+                               continue;
 
-                       if(targPos_x + targSize_x - myPos_x < myPos_y + mySize_y - targPos_y && Check_X) // push it to the side
-                               mySize_x = resizeorigin_x - (targPos_x + targSize_x);
-                       else if(Check_Y) // push it upwards
-                               mySize_y = targPos_y - resizeorigin_y;
+                       dist_x = targPos_x - resizeorigin_x;
+                       dist_y = resizeorigin_y - targEndPos_y;
+                       if (dist_y < 0 || dist_x / dist_y > ratio)
+                               mySize_x = min(mySize_x, dist_x);
+                       else
+                               mySize_y = min(mySize_y, dist_y);
                }
-               else if(myCenter_x < targCenter_x && myCenter_y > targCenter_y) // bottom left
+               else if (resizeCorner == 3)
                {
-                       //if(!HUD_Panel_CheckValidity_of_ResizeSuggestion(id, eX * (targPos_x - resizeorigin_x) + eY * (resizeorigin_y - (targPos_y + targSize_y))))
-                       //      continue;
+                       if (resizeorigin_x < targPos_x)
+                               continue;
+                       if (resizeorigin_y > targEndPos_y)
+                               continue;
+                       if (targEndPos_x < resizeorigin_x - mySize_x)
+                               continue;
+                       if (targPos_y > resizeorigin_y + mySize_y)
+                               continue;
 
-                       if(myPos_x + mySize_x - targPos_x < targPos_y + targSize_y - myPos_y && Check_X) // push it to the side
-                               mySize_x = targPos_x - resizeorigin_x;
-                       else if(Check_Y) // push it upwards
-                               mySize_y = resizeorigin_y - (targPos_y + targSize_y);
+                       dist_x = resizeorigin_x - targEndPos_x;
+                       dist_y = targPos_y - resizeorigin_y;
+                       if (dist_y < 0 || dist_x / dist_y > ratio)
+                               mySize_x = min(mySize_x, dist_x);
+                       else
+                               mySize_y = min(mySize_y, dist_y);
                }
-               else if(myCenter_x > targCenter_x && myCenter_y > targCenter_y) // bottom right
+               else if (resizeCorner == 4)
                {
-                       //if(!HUD_Panel_CheckValidity_of_ResizeSuggestion(id, eX * (resizeorigin_x - (targPos_x + targSize_x)) + eY * (resizeorigin_y - (targPos_y + targSize_y))))
-                       //      continue;
+                       if (resizeorigin_x > targEndPos_x)
+                               continue;
+                       if (resizeorigin_y > targEndPos_y)
+                               continue;
+                       if (targPos_x > resizeorigin_x + mySize_x)
+                               continue;
+                       if (targPos_y > resizeorigin_y + mySize_y)
+                               continue;
 
-                       if(targPos_x + targSize_x - myPos_x < targPos_y + targSize_y - myPos_y && Check_X) // push it to the side
-                               mySize_x = resizeorigin_x - (targPos_x + targSize_x);
-                       else if(Check_Y) // push it upwards
-                               mySize_y = resizeorigin_y - (targPos_y + targSize_y);
+                       dist_x = targPos_x - resizeorigin_x;
+                       dist_y = targPos_y - resizeorigin_y;
+                       if (dist_y < 0 || dist_x / dist_y > ratio)
+                               mySize_x = min(mySize_x, dist_x);
+                       else
+                               mySize_y = min(mySize_y, dist_y);
                }
+               if(cvar("hud_configure_checkcollisions_debug"))
+                       drawfill(targPos + '1 1 0' * targBorder, targSize - '2 2 0' * targBorder, '1 1 0', .3, DRAWFLAG_NORMAL);
        }
-
        return mySize;
 }
 
-void HUD_Panel_SetPosSize(float id, vector resizeorigin)
+void HUD_Panel_SetPosSize(float id)
 {
+       vector resizeorigin;
+       resizeorigin = panel_click_resizeorigin;
        vector mySize, myPos;
 
        if(resizeCorner == 1) {
@@ -1196,9 +1173,26 @@ void HUD_Panel_SetPosSize(float id, vector resizeorigin)
        // cap against panel's own limits
        vector minSize;
        minSize = HUD_Panel_GetMinSize(id); // mySize_x at least minSize_x * mySize_y, and vice versa
-
-       mySize_x = max(minSize_x * mySize_y, mySize_x);
-       mySize_y = max(minSize_y * mySize_x, mySize_y);
+       float fixedRatio;
+       if(!minSize_x && minSize_y)
+       {
+               minSize_x = 1/minSize_y;
+               fixedRatio = minSize_x;
+               mySize_x = max(minSize_x * mySize_y, mySize_x);
+               mySize_y = max(minSize_y * mySize_x, mySize_y);
+       }
+       else if(minSize_x && !minSize_y) // hybrid aspect ratio, currently supported only in one dimension
+       {
+               if (mySize_x/mySize_y < minSize_x) // resizing in x direction allows free aspect ratio
+               {
+                       fixedRatio = minSize_x;
+                       minSize_y = 1/minSize_x;
+                       mySize_y = max(minSize_y * mySize_x, mySize_y);
+                       mySize_x = max(minSize_x * mySize_y, mySize_x);
+               }
+               else
+                       fixedRatio = -minSize_x; //negative so that it will be used ONLY after checkResize
+       }
 
        // collision testing|
        // -----------------+
@@ -1226,15 +1220,49 @@ void HUD_Panel_SetPosSize(float id, vector resizeorigin)
        mySize_x = min(vid_conwidth - myPos_x, mySize_x); 
        mySize_y = min(vid_conheight - myPos_y, mySize_y); 
 
-       if(cvar("hud_configure_checkcollisions"))
-               mySize = HUD_Panel_CheckResize(id, myPos, mySize, resizeorigin);
+       if(cvar("hud_configure_checkcollisions_debug"))
+               drawfill(myPos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
 
+       // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
        if(cvar("hud_configure_grid"))
        {
                mySize_x = floor(mySize_x/cvar("hud_configure_grid_x") + 0.5) * cvar("hud_configure_grid_x");
                mySize_y = floor(mySize_y/cvar("hud_configure_grid_y") + 0.5) * cvar("hud_configure_grid_y");
        }
 
+       if (fixedRatio > 0)
+       {
+               // keep aspect ratio _MAXIMIZING_ the size
+               if (mySize_x / mySize_y > fixedRatio)
+                       mySize_y = mySize_x / fixedRatio;
+               else
+                       mySize_x = mySize_y * fixedRatio;
+       }
+
+       if(cvar("hud_configure_checkcollisions"))
+       {
+               if (fixedRatio > 0)
+               {
+                       mySize = HUD_Panel_CheckResize(id, mySize, resizeorigin, fixedRatio);
+                       // restore again aspect ratio, _minimizing_ the size
+                       if (mySize_x / mySize_y < fixedRatio)
+                               mySize_y = mySize_x / fixedRatio;
+                       else
+                               mySize_x = mySize_y * fixedRatio;
+               }
+               else
+               {
+                       mySize = HUD_Panel_CheckResize(id, mySize, resizeorigin, mySize_x / mySize_y);
+                       if (fixedRatio < 0)
+                       {
+                               fixedRatio = -fixedRatio;
+                               // restore again aspect ratio, _minimizing_ the size
+                               if (mySize_x / mySize_y < fixedRatio)
+                                       mySize_y = mySize_x / fixedRatio;
+                       }
+               }
+       }
+
        // do another pos check, as size might have changed by now
        if(resizeCorner == 1) {
                myPos_x = resizeorigin_x - mySize_x;
@@ -1250,6 +1278,10 @@ void HUD_Panel_SetPosSize(float id, vector resizeorigin)
                myPos_y = resizeorigin_y;
        }
 
+       if(cvar("hud_configure_checkcollisions_debug"))
+       if(cvar("hud_configure_checkcollisions"))
+               drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
+
        string s;
        s = strcat(ftos(mySize_x/vid_conwidth), " ", ftos(mySize_y/vid_conheight));
        cvar_set(strcat("hud_", HUD_Panel_GetName(id), "_size"), s);
@@ -1408,10 +1440,13 @@ void HUD_Panel_Mouse()
                                        }       
                                }
 
+                               if(cvar("hud_configure_checkcollisions_debug"))
+                                       drawfill(panelPos, panelSize, '1 0 0', .3, DRAWFLAG_NORMAL);
+
                                if(highlightedAction == 1)
                                        HUD_Panel_SetPos(i, mousepos - panel_click_distance);
                                else if(highlightedAction == 2)
-                                       HUD_Panel_SetPosSize(i, panel_click_resizeorigin);
+                                       HUD_Panel_SetPosSize(i);
                        }
                }