LCOV - code coverage report
Current view: top level - source/gui/SettingTypes - CGUISize.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 61 108 56.5 %
Date: 2023-01-19 00:18:29 Functions: 4 7 57.1 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "CGUISize.h"
      21             : 
      22             : #include "gui/Scripting/JSInterface_GUISize.h"
      23             : #include "ps/CLogger.h"
      24             : #include "ps/CStr.h"
      25             : #include "scriptinterface/Object.h"
      26             : #include "scriptinterface/ScriptInterface.h"
      27             : 
      28          17 : CGUISize::CGUISize()
      29          17 :     : pixel(), percent()
      30             : {
      31          17 : }
      32             : 
      33           6 : CGUISize::CGUISize(const CRect& pixel, const CRect& percent)
      34           6 :     : pixel(pixel), percent(percent)
      35             : {
      36           6 : }
      37             : 
      38           0 : CGUISize CGUISize::Full()
      39             : {
      40           0 :     return CGUISize(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
      41             : }
      42             : 
      43           4 : CRect CGUISize::GetSize(const CRect& parent) const
      44             : {
      45             :     // If it's a 0 0 100% 100% we need no calculations
      46           4 :     if (percent == CRect(0.f, 0.f, 100.f, 100.f) && pixel == CRect())
      47           0 :         return parent;
      48             : 
      49           4 :     CRect client;
      50             : 
      51             :     // This should probably be cached and not calculated all the time for every object.
      52           4 :     client.left =   parent.left + (parent.right-parent.left)*percent.left/100.f + pixel.left;
      53           4 :     client.top =    parent.top + (parent.bottom-parent.top)*percent.top/100.f + pixel.top;
      54           4 :     client.right =  parent.left + (parent.right-parent.left)*percent.right/100.f + pixel.right;
      55           4 :     client.bottom = parent.top + (parent.bottom-parent.top)*percent.bottom/100.f + pixel.bottom;
      56             : 
      57           4 :     return client;
      58             : }
      59             : 
      60          11 : bool CGUISize::FromString(const CStr& Value)
      61             : {
      62             :     /*
      63             :      * GUISizes contain a left, top, right, and bottom
      64             :      *  for example: "50%-150 10%+9 50%+150 10%+25" means
      65             :      *  the left edge is at 50% minus 150 pixels, the top
      66             :      *  edge is at 10% plus 9 pixels, the right edge is at
      67             :      *  50% plus 150 pixels, and the bottom edge is at 10%
      68             :      *  plus 25 pixels.
      69             :      * All four coordinates are required and can be
      70             :      *  defined only in pixels, only in percents, or some
      71             :      *  combination of both.
      72             :      */
      73             : 
      74             :     // Check the input is only numeric
      75          11 :     const char* input = Value.c_str();
      76          22 :     CStr buffer;
      77          11 :     unsigned int coord = 0;
      78          11 :     float pixels[4] = {0, 0, 0, 0};
      79          11 :     float percents[4] = {0, 0, 0, 0};
      80         187 :     for (unsigned int i = 0; i < Value.length(); ++i)
      81             :     {
      82         180 :         switch (input[i])
      83             :         {
      84         107 :         case '.':
      85             :         case '0':
      86             :         case '1':
      87             :         case '2':
      88             :         case '3':
      89             :         case '4':
      90             :         case '5':
      91             :         case '6':
      92             :         case '7':
      93             :         case '8':
      94             :         case '9':
      95         107 :             buffer.push_back(input[i]);
      96         107 :             break;
      97           5 :         case '+':
      98           5 :             pixels[coord] += buffer.ToFloat();
      99           5 :             buffer = "+";
     100           5 :             break;
     101          20 :         case '-':
     102          20 :             pixels[coord] += buffer.ToFloat();
     103          20 :             buffer = "-";
     104          20 :             break;
     105          20 :         case '%':
     106          20 :             percents[coord] += buffer.ToFloat();
     107          20 :             buffer = "";
     108          20 :             break;
     109          25 :         case ' ':
     110          25 :             pixels[coord] += buffer.ToFloat();
     111          25 :             buffer = "";
     112          25 :             ++coord;
     113          25 :             break;
     114           3 :         default:
     115           3 :             LOGERROR("CGUISize definition may only include numbers. Your input: '%s'", Value.c_str());
     116           3 :             return false;
     117             :         }
     118         177 :         if (coord > 3)
     119             :         {
     120           1 :             LOGERROR("Too many CGUISize parameters (4 max). Your input: '%s'", Value.c_str());
     121           1 :             return false;
     122             :         }
     123             :     }
     124             : 
     125           7 :     if (coord < 3)
     126             :     {
     127           1 :         LOGERROR("Too few CGUISize parameters (4 min). Your input: '%s'", Value.c_str());
     128           1 :         return false;
     129             :     }
     130             : 
     131             :     // Now that we're at the end of the string, flush the remaining buffer.
     132           6 :     pixels[coord] += buffer.ToFloat();
     133             : 
     134             :     // Now store the coords in the right place
     135           6 :     pixel.left =        pixels[0];
     136           6 :     pixel.top =         pixels[1];
     137           6 :     pixel.right =       pixels[2];
     138           6 :     pixel.bottom =      pixels[3];
     139           6 :     percent.left =      percents[0];
     140           6 :     percent.top =       percents[1];
     141           6 :     percent.right =     percents[2];
     142           6 :     percent.bottom =    percents[3];
     143           6 :     return true;
     144             : }
     145             : 
     146           0 : void CGUISize::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const
     147             : {
     148           0 :     const ScriptInterface& scriptInterface = rq.GetScriptInterface();
     149           0 :     ret.setObjectOrNull(scriptInterface.CreateCustomObject("GUISize"));
     150             : 
     151           0 :     if (!ret.isObject())
     152             :     {
     153           0 :         ScriptException::Raise(rq, "CGUISize value is not an Object");
     154           0 :         return;
     155             :     }
     156             : 
     157           0 :     JS::RootedObject obj(rq.cx, &ret.toObject());
     158           0 :     if (!JS_InstanceOf(rq.cx, obj, &JSI_GUISize::JSI_class, nullptr))
     159             :     {
     160           0 :         ScriptException::Raise(rq, "CGUISize value is not a CGUISize class instance");
     161           0 :         return;
     162             :     }
     163             : 
     164             : #define P(x, y, z)\
     165             :     if (!Script::SetProperty(rq, ret, #z, x.y)) \
     166             :     { \
     167             :         ScriptException::Raise(rq, "Could not SetProperty '%s'", #z); \
     168             :         return; \
     169             :     }
     170           0 :     P(pixel, left, left);
     171           0 :     P(pixel, top, top);
     172           0 :     P(pixel, right, right);
     173           0 :     P(pixel, bottom, bottom);
     174           0 :     P(percent, left, rleft);
     175           0 :     P(percent, top, rtop);
     176           0 :     P(percent, right, rright);
     177           0 :     P(percent, bottom, rbottom);
     178             : #undef P
     179             : }
     180             : 
     181           0 : bool CGUISize::FromJSVal(const ScriptRequest& rq, JS::HandleValue v)
     182             : {
     183           0 :     if (v.isString())
     184             :     {
     185           0 :         CStrW str;
     186           0 :         if (!Script::FromJSVal(rq, v, str))
     187             :         {
     188           0 :             LOGERROR("CGUISize could not read JS string");
     189           0 :             return false;
     190             :         }
     191             : 
     192           0 :         if (!FromString(str.ToUTF8()))
     193             :         {
     194           0 :             LOGERROR("CGUISize could not parse JS string");
     195           0 :             return false;
     196             :         }
     197           0 :         return true;
     198             :     }
     199             : 
     200           0 :     if (!v.isObject())
     201             :     {
     202           0 :         LOGERROR("CGUISize value is not an String, nor Object");
     203           0 :         return false;
     204             :     }
     205             : 
     206           0 :     JS::RootedObject obj(rq.cx, &v.toObject());
     207           0 :     if (!JS_InstanceOf(rq.cx, obj, &JSI_GUISize::JSI_class, nullptr))
     208             :     {
     209           0 :         LOGERROR("CGUISize value is not a CGUISize class instance");
     210           0 :         return false;
     211             :     }
     212             : 
     213             : #define P(x, y, z) \
     214             :     if (!Script::GetProperty(rq, v, #z, x.y))\
     215             :     {\
     216             :         LOGERROR("CGUISize could not get object property '%s'", #z);\
     217             :         return false;\
     218             :     }
     219             : 
     220           0 :     P(pixel, left, left);
     221           0 :     P(pixel, top, top);
     222           0 :     P(pixel, right, right);
     223           0 :     P(pixel, bottom, bottom);
     224           0 :     P(percent, left, rleft);
     225           0 :     P(percent, top, rtop);
     226           0 :     P(percent, right, rright);
     227           0 :     P(percent, bottom, rbottom);
     228             : #undef P
     229             : 
     230           0 :     return true;
     231             : }

Generated by: LCOV version 1.13