aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra')
-rw-r--r--linden/indra/llmath/CMakeLists.txt4
-rw-r--r--linden/indra/llmath/llcalc.cpp155
-rw-r--r--linden/indra/llmath/llcalc.h85
-rw-r--r--linden/indra/llmath/llcalcparser.cpp45
-rw-r--r--linden/indra/llmath/llcalcparser.h155
-rw-r--r--linden/indra/llui/lllineeditor.cpp33
-rw-r--r--linden/indra/llui/lllineeditor.h4
-rw-r--r--linden/indra/llui/llspinctrl.cpp17
-rw-r--r--linden/indra/newview/llappviewer.cpp3
-rw-r--r--linden/indra/newview/llpanelface.cpp20
-rw-r--r--linden/indra/newview/llpanelobject.cpp49
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/floater_tools.xml18
12 files changed, 569 insertions, 19 deletions
diff --git a/linden/indra/llmath/CMakeLists.txt b/linden/indra/llmath/CMakeLists.txt
index 6a329fa..e5ec3e1 100644
--- a/linden/indra/llmath/CMakeLists.txt
+++ b/linden/indra/llmath/CMakeLists.txt
@@ -11,6 +11,8 @@ include_directories(
11 11
12set(llmath_SOURCE_FILES 12set(llmath_SOURCE_FILES
13 llbboxlocal.cpp 13 llbboxlocal.cpp
14 llcalc.cpp
15 llcalcparser.cpp
14 llcamera.cpp 16 llcamera.cpp
15 llcoordframe.cpp 17 llcoordframe.cpp
16 llline.cpp 18 llline.cpp
@@ -40,6 +42,8 @@ set(llmath_HEADER_FILES
40 camera.h 42 camera.h
41 coordframe.h 43 coordframe.h
42 llbboxlocal.h 44 llbboxlocal.h
45 llcalc.h
46 llcalcparser.h
43 llcamera.h 47 llcamera.h
44 llcoord.h 48 llcoord.h
45 llcoordframe.h 49 llcoordframe.h
diff --git a/linden/indra/llmath/llcalc.cpp b/linden/indra/llmath/llcalc.cpp
new file mode 100644
index 0000000..feb072a
--- /dev/null
+++ b/linden/indra/llmath/llcalc.cpp
@@ -0,0 +1,155 @@
1/*
2 * LLCalc.cpp
3 * SecondLife
4 *
5 * Created by Aimee Walton on 28/09/2008.
6 * Copyright 2008 Aimee Walton.
7 *
8 */
9
10#include "linden_common.h"
11
12#include "llcalc.h"
13
14#include <boost/spirit/core.hpp>
15#include <boost/spirit/error_handling.hpp>
16
17#include "llcalcparser.h"
18#include "llmath.h"
19
20
21// Variable names for use in the build floater
22const char* LLCalc::X_POS = "X";
23const char* LLCalc::Y_POS = "Y";
24const char* LLCalc::Z_POS = "Z";
25const char* LLCalc::X_SCALE = "XS";
26const char* LLCalc::Y_SCALE = "YS";
27const char* LLCalc::Z_SCALE = "ZS";
28const char* LLCalc::X_ROT = "XR";
29const char* LLCalc::Y_ROT = "YR";
30const char* LLCalc::Z_ROT = "ZR";
31const char* LLCalc::HOLLOW = "HLW";
32const char* LLCalc::CUT_BEGIN = "CB";
33const char* LLCalc::CUT_END = "CE";
34const char* LLCalc::PATH_BEGIN = "PB";
35const char* LLCalc::PATH_END = "PE";
36const char* LLCalc::TWIST_BEGIN = "TB";
37const char* LLCalc::TWIST_END = "TE";
38const char* LLCalc::X_SHEAR = "XSH";
39const char* LLCalc::Y_SHEAR = "YSH";
40const char* LLCalc::X_TAPER = "XTP";
41const char* LLCalc::Y_TAPER = "YTP";
42const char* LLCalc::RADIUS_OFFSET = "ROF";
43const char* LLCalc::REVOLUTIONS = "REV";
44const char* LLCalc::SKEW = "SKW";
45const char* LLCalc::X_HOLE = "XHL";
46const char* LLCalc::Y_HOLE = "YHL";
47const char* LLCalc::TEX_U_SCALE = "TSU";
48const char* LLCalc::TEX_V_SCALE = "TSV";
49const char* LLCalc::TEX_U_OFFSET = "TOU";
50const char* LLCalc::TEX_V_OFFSET = "TOV";
51const char* LLCalc::TEX_ROTATION = "TROT";
52const char* LLCalc::TEX_TRANSPARENCY = "TRNS";
53const char* LLCalc::TEX_GLOW = "GLOW";
54
55
56LLCalc* LLCalc::sInstance = NULL;
57
58LLCalc::LLCalc() : mLastErrorPos(0)
59{
60// mUserVariables = new calc_map_t;
61 mVariables = new calc_map_t;
62 mConstants = new calc_map_t;
63
64 // Init table of constants
65 (*mConstants)["PI"] = F_PI;
66 (*mConstants)["TWO_PI"] = F_TWO_PI;
67 (*mConstants)["PI_BY_TWO"] = F_PI_BY_TWO;
68 (*mConstants)["SQRT2"] = F_SQRT2;
69 (*mConstants)["DEG_TO_RAD"] = DEG_TO_RAD;
70 (*mConstants)["RAD_TO_DEG"] = RAD_TO_DEG;
71 (*mConstants)["GRAVITY"] = GRAVITY;
72}
73
74LLCalc::~LLCalc()
75{
76 delete mConstants;
77 delete mVariables;
78// delete mUserVariables;
79}
80
81//static
82void LLCalc::cleanUp()
83{
84 delete sInstance;
85 sInstance = NULL;
86}
87
88//static
89LLCalc* LLCalc::getInstance()
90{
91 if (!sInstance) sInstance = new LLCalc();
92 return sInstance;
93}
94
95void LLCalc::setVar(const std::string& name, const F32& value)
96{
97 (*mVariables)[name] = value;
98}
99
100void LLCalc::clearVar(const std::string& name)
101{
102 mVariables->erase(name);
103}
104
105void LLCalc::clearAllVariables()
106{
107 mVariables->clear();
108}
109
110/*
111void LLCalc::updateVariables(LLSD& vars)
112{
113 LLSD::map_iterator cIt = vars.beginMap();
114 for(; cIt != vars.endMap(); cIt++)
115 {
116 setVar(cIt->first, (F32)(LLSD::Real)cIt->second);
117 }
118}
119*/
120
121bool LLCalc::evalString(const std::string& expression, F32& result)
122{
123 using namespace boost::spirit;
124
125 std::string expr_upper = expression;
126 LLStringUtil::toUpper(expr_upper);
127
128 LLCalcParser calc(result, mConstants, mVariables);
129
130 mLastErrorPos = 0;
131 std::string::iterator start = expr_upper.begin();
132 parse_info<std::string::iterator> info;
133
134 try
135 {
136 info = parse(start, expr_upper.end(), calc, space_p);
137 lldebugs << "Math expression: " << expression << " = " << result << llendl;
138 }
139 catch(parser_error<std::string, std::string::iterator> &e)
140 {
141 mLastErrorPos = e.where - expr_upper.begin();
142
143 llinfos << "Calc parser exception: " << e.descriptor << " at " << mLastErrorPos << " in expression: " << expression << llendl;
144 return false;
145 }
146
147 if (!info.full)
148 {
149 mLastErrorPos = info.stop - expr_upper.begin();
150 llinfos << "Unhandled syntax error at " << mLastErrorPos << " in expression: " << expression << llendl;
151 return false;
152 }
153
154 return true;
155}
diff --git a/linden/indra/llmath/llcalc.h b/linden/indra/llmath/llcalc.h
new file mode 100644
index 0000000..a376895
--- /dev/null
+++ b/linden/indra/llmath/llcalc.h
@@ -0,0 +1,85 @@
1/*
2 * LLCalc.h
3 * SecondLife
4 *
5 * Created by Aimee Walton on 28/09/2008.
6 * Copyright 2008 Aimee Walton.
7 *
8 */
9
10#ifndef LL_CALC_H
11#define LL_CALC_H
12
13#include <map>
14#include <string>
15
16//#include "llsd.h"
17
18class LLCalc
19{
20public:
21 LLCalc();
22 ~LLCalc();
23
24 // Variable name constants
25 static const char* X_POS;
26 static const char* Y_POS;
27 static const char* Z_POS;
28 static const char* X_SCALE;
29 static const char* Y_SCALE;
30 static const char* Z_SCALE;
31 static const char* X_ROT;
32 static const char* Y_ROT;
33 static const char* Z_ROT;
34 static const char* HOLLOW;
35 static const char* CUT_BEGIN;
36 static const char* CUT_END;
37 static const char* PATH_BEGIN;
38 static const char* PATH_END;
39 static const char* TWIST_BEGIN;
40 static const char* TWIST_END;
41 static const char* X_SHEAR;
42 static const char* Y_SHEAR;
43 static const char* X_TAPER;
44 static const char* Y_TAPER;
45 static const char* RADIUS_OFFSET;
46 static const char* REVOLUTIONS;
47 static const char* SKEW;
48 static const char* X_HOLE;
49 static const char* Y_HOLE;
50 static const char* TEX_U_SCALE;
51 static const char* TEX_V_SCALE;
52 static const char* TEX_U_OFFSET;
53 static const char* TEX_V_OFFSET;
54 static const char* TEX_ROTATION;
55 static const char* TEX_TRANSPARENCY;
56 static const char* TEX_GLOW;
57
58 void setVar(const std::string& name, const F32& value);
59 void clearVar(const std::string& name);
60 void clearAllVariables();
61// void updateVariables(LLSD& vars);
62
63 bool evalString(const std::string& expression, F32& result);
64 std::string::size_type getLastErrorPos() { return mLastErrorPos; }
65
66 static LLCalc* getInstance();
67 static void cleanUp();
68
69 typedef std::map<std::string, F32> calc_map_t;
70
71private:
72 std::string::size_type mLastErrorPos;
73
74 calc_map_t* mConstants;
75 calc_map_t* mVariables;
76
77 // *TODO: Add support for storing user defined variables, and stored functions.
78 // Will need UI work, and a means to save them between sessions.
79// calc_map_t* mUserVariables;
80
81 // "There shall be only one"
82 static LLCalc* sInstance;
83};
84
85#endif // LL_CALC_H
diff --git a/linden/indra/llmath/llcalcparser.cpp b/linden/indra/llmath/llcalcparser.cpp
new file mode 100644
index 0000000..1546c09
--- /dev/null
+++ b/linden/indra/llmath/llcalcparser.cpp
@@ -0,0 +1,45 @@
1/*
2 * LLCalcParser.cpp
3 * SecondLife
4 *
5 * Created by Aimee Walton on 28/09/2008.
6 * Copyright 2008 Aimee Walton.
7 *
8 */
9
10#include "linden_common.h"
11
12#include "llcalcparser.h"
13
14F32 LLCalcParser::lookup(const std::string::iterator& start, const std::string::iterator& end) const
15{
16 LLCalc::calc_map_t::iterator iter;
17
18 std::string name(start, end);
19
20 if (mConstants)
21 {
22 iter = mConstants->find(name);
23 if (iter != mConstants->end())
24 {
25 return (*iter).second;
26 }
27 }
28 else
29 {
30 // This should never happen!
31 boost::spirit::throw_(end, std::string("Missing constants table"));
32 }
33
34 if (mVariables)
35 {
36 iter = mVariables->find(name);
37 if (iter != mVariables->end())
38 {
39 return (*iter).second;
40 }
41 }
42
43 boost::spirit::throw_(end, std::string("Unknown symbol " + name));
44 return 0.f;
45}
diff --git a/linden/indra/llmath/llcalcparser.h b/linden/indra/llmath/llcalcparser.h
new file mode 100644
index 0000000..c405b62
--- /dev/null
+++ b/linden/indra/llmath/llcalcparser.h
@@ -0,0 +1,155 @@
1/*
2 * LLCalcParser.h
3 * SecondLife
4 *
5 * Created by Aimee Walton on 28/09/2008.
6 * Copyright 2008 Aimee Walton.
7 *
8 */
9
10#ifndef LL_CALCPARSER_H
11#define LL_CALCPARSER_H
12
13#include <boost/spirit/attribute.hpp>
14#include <boost/spirit/core.hpp>
15#include <boost/spirit/error_handling.hpp>
16#include <boost/spirit/iterator/position_iterator.hpp>
17#include <boost/spirit/phoenix/binders.hpp>
18//#include <boost/spirit/symbols/symbols.hpp>
19#include <map>
20#include <string>
21
22#include "llcalc.h"
23#include "llmath.h"
24
25struct LLCalcParser : boost::spirit::grammar<LLCalcParser>
26{
27 LLCalcParser(F32& result, LLCalc::calc_map_t* constants, LLCalc::calc_map_t* vars) :
28 mResult(result), mConstants(constants), mVariables(vars) {};
29
30 struct value_closure : boost::spirit::closure<value_closure, F32>
31 {
32 member1 value;
33 };
34
35 template <typename ScannerT>
36 struct definition
37 {
38 // Rule declarations
39 boost::spirit::rule<ScannerT> statement, identifier;
40 boost::spirit::rule<ScannerT, value_closure::context_t> expression, term,
41 power,
42 unary_expr,
43 factor,
44 /*unary_func,
45 /binary_func,*/
46 group;
47
48 // start() should return the starting symbol
49 boost::spirit::rule<ScannerT> const& start() const { return statement; }
50
51 definition(LLCalcParser const& self)
52 {
53 using namespace boost::spirit;
54 using namespace phoenix;
55
56 assertion<std::string> assert_domain("Domain error");
57// assertion<std::string> assert_symbol("Unknown symbol");
58 assertion<std::string> assert_syntax("Syntax error");
59
60 identifier =
61 lexeme_d[(alpha_p | '_') >> *(alnum_p | '_')]
62 ;
63
64 group =
65 '(' >> expression[group.value = arg1] >> assert_syntax(ch_p(')'))
66 ;
67
68 /*unary_func =
69 ((str_p("SIN") >> '(' >> expression[unary_func.value = bind(&sin)(DEG_TO_RAD * arg1)]) |
70 (str_p("COS") >> '(' >> expression[unary_func.value = bind(&cos)(DEG_TO_RAD * arg1)]) |
71 (str_p("TAN") >> '(' >> expression[unary_func.value = bind(&tan)(DEG_TO_RAD * arg1)]) |
72 (str_p("ASIN") >> '(' >> expression[unary_func.value = (bind(&asin)(arg1)) * RAD_TO_DEG]) |
73 (str_p("ACOS") >> '(' >> expression[unary_func.value = bind(&acos)(arg1) * RAD_TO_DEG]) |
74 (str_p("ATAN") >> '(' >> expression[unary_func.value = bind(&atan)(arg1) * RAD_TO_DEG]) |
75 (str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&sqrt)(arg1)]) |
76 (str_p("LOG") >> '(' >> expression[unary_func.value = bind(&log)(arg1)]) |
77 (str_p("EXP") >> '(' >> expression[unary_func.value = bind(&exp)(arg1)]) |
78 (str_p("ABS") >> '(' >> expression[unary_func.value = bind(&fabs)(arg1)])
79 ) >> assert_syntax(ch_p(')'))
80 ;
81
82 binary_func =
83 ((str_p("ATAN2") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
84 expression[binary_func.value = bind(&atan2)(binary_func.value, arg1) * RAD_TO_DEG]) |
85 (str_p("MIN") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
86 expression[binary_func.value = bind(&LLCalcParser::min)(self, binary_func.value, arg1)]) |
87 (str_p("MAX") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
88 expression[binary_func.value = bind(&LLCalcParser::max)(self, binary_func.value, arg1)])
89 ) >> assert_syntax(ch_p(')'))
90 ;*/
91
92 // *TODO: Localisation of the decimal point?
93 // Problem, LLLineEditor::postvalidateFloat accepts a comma when appropriate
94 // for the current locale. However to do that here could clash with using
95 // the comma as a separator when passing arguments to functions.
96 factor =
97 (ureal_p[factor.value = arg1] |
98 group[factor.value = arg1] |
99 /*unary_func[factor.value = arg1] |
100 binary_func[factor.value = arg1] |*/
101 // Lookup throws an Unknown Symbol error if it is unknown, while this works fine,
102 // would be "neater" to handle symbol lookup from here with an assertive parser.
103// constants_p[factor.value = arg1]|
104 identifier[factor.value = bind(&LLCalcParser::lookup)(self, arg1, arg2)]
105 ) >>
106 // Detect and throw math errors.
107 assert_domain(eps_p(bind(&LLCalcParser::checkNaN)(self, factor.value)))
108 ;
109
110 unary_expr =
111 !ch_p('+') >> factor[unary_expr.value = arg1] |
112 '-' >> factor[unary_expr.value = -arg1]
113 ;
114
115 power =
116 unary_expr[power.value = arg1] >>
117 *('^' >> assert_syntax(unary_expr[power.value = bind(&powf)(power.value, arg1)]))
118 ;
119
120 term =
121 power[term.value = arg1] >>
122 *(('*' >> assert_syntax(power[term.value *= arg1])) |
123 ('/' >> assert_syntax(power[term.value /= arg1]))
124 )
125 ;
126
127 expression =
128 assert_syntax(term[expression.value = arg1]) >>
129 *(('+' >> assert_syntax(term[expression.value += arg1])) |
130 ('-' >> assert_syntax(term[expression.value -= arg1]))
131 )
132 ;
133
134 statement =
135 !ch_p('=') >> ( expression )[var(self.mResult) = arg1] >> (end_p)
136 ;
137 }
138 };
139
140private:
141 // Member functions for semantic actions
142 F32 lookup(const std::string::iterator&, const std::string::iterator&) const;
143 F32 min(const F32& a, const F32& b) const { return llmin(a, b); }
144 F32 max(const F32& a, const F32& b) const { return llmax(a, b); }
145
146 bool checkNaN(const F32& a) const { return !llisnan(a); }
147
148 LLCalc::calc_map_t* mConstants;
149 LLCalc::calc_map_t* mVariables;
150// LLCalc::calc_map_t* mUserVariables;
151
152 F32& mResult;
153};
154
155#endif // LL_CALCPARSER_H
diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp
index 12d1929..9c8ee94 100644
--- a/linden/indra/llui/lllineeditor.cpp
+++ b/linden/indra/llui/lllineeditor.cpp
@@ -41,6 +41,7 @@
41#include "llgl.h" 41#include "llgl.h"
42#include "lltimer.h" 42#include "lltimer.h"
43 43
44#include "llcalc.h"
44//#include "llclipboard.h" 45//#include "llclipboard.h"
45#include "llcontrol.h" 46#include "llcontrol.h"
46#include "llbutton.h" 47#include "llbutton.h"
@@ -129,6 +130,7 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
129 mDrawAsterixes( FALSE ), 130 mDrawAsterixes( FALSE ),
130 mHandleEditKeysDirectly( FALSE ), 131 mHandleEditKeysDirectly( FALSE ),
131 mSelectAllonFocusReceived( FALSE ), 132 mSelectAllonFocusReceived( FALSE ),
133 mSelectAllonCommit( TRUE ),
132 mPassDelete(FALSE), 134 mPassDelete(FALSE),
133 mReadOnly(FALSE), 135 mReadOnly(FALSE),
134 mImage( sImage ), 136 mImage( sImage ),
@@ -226,7 +228,10 @@ void LLLineEditor::onCommit()
226 updateHistory(); 228 updateHistory();
227 229
228 LLUICtrl::onCommit(); 230 LLUICtrl::onCommit();
229 selectAll(); 231
232 // Selection on commit needs to be turned off when evaluating maths
233 // expressions, to allow indication of the error position
234 if (mSelectAllonCommit) selectAll();
230} 235}
231 236
232 237
@@ -2082,6 +2087,32 @@ BOOL LLLineEditor::prevalidateASCII(const LLWString &str)
2082 return rv; 2087 return rv;
2083} 2088}
2084 2089
2090BOOL LLLineEditor::evaluateFloat()
2091{
2092 bool success;
2093 F32 result = 0.f;
2094 std::string expr = getText();
2095
2096 success = LLCalc::getInstance()->evalString(expr, result);
2097
2098 if (!success)
2099 {
2100 // Move the cursor to near the error on failure
2101 setCursor(LLCalc::getInstance()->getLastErrorPos());
2102 // *TODO: Translated error message indicating the type of error? Select error text?
2103 }
2104 else
2105 {
2106 // Replace the expression with the result
2107 std::ostringstream result_str;
2108 result_str << result;
2109 setText(result_str.str());
2110 selectAll();
2111 }
2112
2113 return success;
2114}
2115
2085void LLLineEditor::onMouseCaptureLost() 2116void LLLineEditor::onMouseCaptureLost()
2086{ 2117{
2087 endSelection(); 2118 endSelection();
diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h
index 09a240b..6738151 100644
--- a/linden/indra/llui/lllineeditor.h
+++ b/linden/indra/llui/lllineeditor.h
@@ -188,6 +188,7 @@ public:
188 188
189 void setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; } 189 void setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; }
190 void setSelectAllonFocusReceived(BOOL b); 190 void setSelectAllonFocusReceived(BOOL b);
191 void setSelectAllonCommit(BOOL b) { mSelectAllonCommit = b; }
191 192
192 void setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data)); 193 void setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data));
193 194
@@ -208,6 +209,8 @@ public:
208 static BOOL prevalidateASCII(const LLWString &str); 209 static BOOL prevalidateASCII(const LLWString &str);
209 210
210 static BOOL postvalidateFloat(const std::string &str); 211 static BOOL postvalidateFloat(const std::string &str);
212
213 BOOL evaluateFloat();
211 214
212 // line history support: 215 // line history support:
213 void setEnableLineHistory( BOOL enabled ) { mHaveHistory = enabled; } // switches line history on or off 216 void setEnableLineHistory( BOOL enabled ) { mHaveHistory = enabled; } // switches line history on or off
@@ -297,6 +300,7 @@ protected:
297 300
298 BOOL mHandleEditKeysDirectly; // If true, the standard edit keys (Ctrl-X, Delete, etc,) are handled here instead of routed by the menu system 301 BOOL mHandleEditKeysDirectly; // If true, the standard edit keys (Ctrl-X, Delete, etc,) are handled here instead of routed by the menu system
299 BOOL mSelectAllonFocusReceived; 302 BOOL mSelectAllonFocusReceived;
303 BOOL mSelectAllonCommit;
300 BOOL mPassDelete; 304 BOOL mPassDelete;
301 305
302 BOOL mReadOnly; 306 BOOL mReadOnly;
diff --git a/linden/indra/llui/llspinctrl.cpp b/linden/indra/llui/llspinctrl.cpp
index a106af4..b12d095 100644
--- a/linden/indra/llui/llspinctrl.cpp
+++ b/linden/indra/llui/llspinctrl.cpp
@@ -49,7 +49,7 @@
49#include "llfocusmgr.h" 49#include "llfocusmgr.h"
50#include "llresmgr.h" 50#include "llresmgr.h"
51 51
52const U32 MAX_STRING_LENGTH = 32; 52const U32 MAX_STRING_LENGTH = 255;
53 53
54static LLRegisterWidget<LLSpinCtrl> r2("spinner"); 54static LLRegisterWidget<LLSpinCtrl> r2("spinner");
55 55
@@ -123,7 +123,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std::
123 mEditor = new LLLineEditor( std::string("SpinCtrl Editor"), editor_rect, LLStringUtil::null, font, 123 mEditor = new LLLineEditor( std::string("SpinCtrl Editor"), editor_rect, LLStringUtil::null, font,
124 MAX_STRING_LENGTH, 124 MAX_STRING_LENGTH,
125 &LLSpinCtrl::onEditorCommit, NULL, NULL, this, 125 &LLSpinCtrl::onEditorCommit, NULL, NULL, this,
126 &LLLineEditor::prevalidateFloat ); 126 &LLLineEditor::prevalidateASCII );
127 mEditor->setFollowsLeft(); 127 mEditor->setFollowsLeft();
128 mEditor->setFollowsBottom(); 128 mEditor->setFollowsBottom();
129 mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this ); 129 mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this );
@@ -132,6 +132,7 @@ LLSpinCtrl::LLSpinCtrl( const std::string& name, const LLRect& rect, const std::
132 // it's easier to understand 132 // it's easier to understand
133 //mEditor->setSelectAllonFocusReceived(TRUE); 133 //mEditor->setSelectAllonFocusReceived(TRUE);
134 mEditor->setIgnoreTab(TRUE); 134 mEditor->setIgnoreTab(TRUE);
135 mEditor->setSelectAllonCommit(FALSE);
135 addChild(mEditor); 136 addChild(mEditor);
136 137
137 updateEditor(); 138 updateEditor();
@@ -292,9 +293,10 @@ void LLSpinCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
292 LLSpinCtrl* self = (LLSpinCtrl*) userdata; 293 LLSpinCtrl* self = (LLSpinCtrl*) userdata;
293 llassert( caller == self->mEditor ); 294 llassert( caller == self->mEditor );
294 295
295 std::string text = self->mEditor->getText(); 296 if( self->mEditor->evaluateFloat() )
296 if( LLLineEditor::postvalidateFloat( text ) )
297 { 297 {
298 std::string text = self->mEditor->getText();
299
298 LLLocale locale(LLLocale::USER_LOCALE); 300 LLLocale locale(LLLocale::USER_LOCALE);
299 F32 val = (F32) atof(text.c_str()); 301 F32 val = (F32) atof(text.c_str());
300 302
@@ -322,9 +324,12 @@ void LLSpinCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
322 success = TRUE; 324 success = TRUE;
323 } 325 }
324 } 326 }
325 self->updateEditor();
326 327
327 if( !success ) 328 if( success )
329 {
330 self->updateEditor();
331 }
332 else
328 { 333 {
329 self->reportInvalidData(); 334 self->reportInvalidData();
330 } 335 }
diff --git a/linden/indra/newview/llappviewer.cpp b/linden/indra/newview/llappviewer.cpp
index 2cf418e..64402e3 100644
--- a/linden/indra/newview/llappviewer.cpp
+++ b/linden/indra/newview/llappviewer.cpp
@@ -109,6 +109,7 @@
109#include "llpostprocess.h" 109#include "llpostprocess.h"
110#include "llwlparammanager.h" 110#include "llwlparammanager.h"
111#include "llwaterparammanager.h" 111#include "llwaterparammanager.h"
112#include "llcalc.h"
112 113
113#include "lldebugview.h" 114#include "lldebugview.h"
114#include "llconsole.h" 115#include "llconsole.h"
@@ -1176,6 +1177,8 @@ bool LLAppViewer::cleanup()
1176 LLNotifyBox::cleanup(); 1177 LLNotifyBox::cleanup();
1177 1178
1178 LLWorldMap::getInstance()->reset(); // release any images 1179 LLWorldMap::getInstance()->reset(); // release any images
1180
1181 LLCalc::cleanUp();
1179 1182
1180 llinfos << "Global stuff deleted" << llendflush; 1183 llinfos << "Global stuff deleted" << llendflush;
1181 1184
diff --git a/linden/indra/newview/llpanelface.cpp b/linden/indra/newview/llpanelface.cpp
index 4742627..e9555c6 100644
--- a/linden/indra/newview/llpanelface.cpp
+++ b/linden/indra/newview/llpanelface.cpp
@@ -35,6 +35,7 @@
35#include "llpanelface.h" 35#include "llpanelface.h"
36 36
37// library includes 37// library includes
38#include "llcalc.h"
38#include "llerror.h" 39#include "llerror.h"
39#include "llfocusmgr.h" 40#include "llfocusmgr.h"
40#include "llrect.h" 41#include "llrect.h"
@@ -381,6 +382,7 @@ void LLPanelFace::sendTextureInfo()
381void LLPanelFace::getState() 382void LLPanelFace::getState()
382{ 383{
383 LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); 384 LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
385 LLCalc* calcp = LLCalc::getInstance();
384 386
385 if( objectp 387 if( objectp
386 && objectp->getPCode() == LL_PCODE_VOLUME 388 && objectp->getPCode() == LL_PCODE_VOLUME
@@ -754,6 +756,15 @@ void LLPanelFace::getState()
754 childSetEnabled("button apply",enabled); 756 childSetEnabled("button apply",enabled);
755 } 757 }
756 } 758 }
759
760 // Set variable values for numeric expressions
761 calcp->setVar(LLCalc::TEX_U_SCALE, childGetValue("TexScaleU").asReal());
762 calcp->setVar(LLCalc::TEX_V_SCALE, childGetValue("TexScaleV").asReal());
763 calcp->setVar(LLCalc::TEX_U_OFFSET, childGetValue("TexOffsetU").asReal());
764 calcp->setVar(LLCalc::TEX_V_OFFSET, childGetValue("TexOffsetV").asReal());
765 calcp->setVar(LLCalc::TEX_ROTATION, childGetValue("TexRot").asReal());
766 calcp->setVar(LLCalc::TEX_TRANSPARENCY, childGetValue("ColorTrans").asReal());
767 calcp->setVar(LLCalc::TEX_GLOW, childGetValue("glow").asReal());
757 } 768 }
758 else 769 else
759 { 770 {
@@ -787,6 +798,15 @@ void LLPanelFace::getState()
787 798
788 childSetEnabled("button align",FALSE); 799 childSetEnabled("button align",FALSE);
789 childSetEnabled("button apply",FALSE); 800 childSetEnabled("button apply",FALSE);
801
802 // Set variable values for numeric expressions
803 calcp->clearVar(LLCalc::TEX_U_SCALE);
804 calcp->clearVar(LLCalc::TEX_V_SCALE);
805 calcp->clearVar(LLCalc::TEX_U_OFFSET);
806 calcp->clearVar(LLCalc::TEX_V_OFFSET);
807 calcp->clearVar(LLCalc::TEX_ROTATION);
808 calcp->clearVar(LLCalc::TEX_TRANSPARENCY);
809 calcp->clearVar(LLCalc::TEX_GLOW);
790 } 810 }
791} 811}
792 812
diff --git a/linden/indra/newview/llpanelobject.cpp b/linden/indra/newview/llpanelobject.cpp
index cc9d969..8efa39a 100644
--- a/linden/indra/newview/llpanelobject.cpp
+++ b/linden/indra/newview/llpanelobject.cpp
@@ -46,6 +46,7 @@
46// project includes 46// project includes
47#include "llagent.h" 47#include "llagent.h"
48#include "llbutton.h" 48#include "llbutton.h"
49#include "llcalc.h"
49#include "llcheckboxctrl.h" 50#include "llcheckboxctrl.h"
50#include "llcolorswatch.h" 51#include "llcolorswatch.h"
51#include "llcombobox.h" 52#include "llcombobox.h"
@@ -341,6 +342,8 @@ void LLPanelObject::getState( )
341 } 342 }
342 } 343 }
343 344
345 LLCalc* calcp = LLCalc::getInstance();
346
344 LLVOVolume *volobjp = NULL; 347 LLVOVolume *volobjp = NULL;
345 if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) 348 if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
346 { 349 {
@@ -357,6 +360,7 @@ void LLPanelObject::getState( )
357 360
358 // Disable all text input fields 361 // Disable all text input fields
359 clearCtrls(); 362 clearCtrls();
363 calcp->clearAllVariables();
360 return; 364 return;
361 } 365 }
362 366
@@ -372,12 +376,18 @@ void LLPanelObject::getState( )
372 mCtrlPosX->set( vec.mV[VX] ); 376 mCtrlPosX->set( vec.mV[VX] );
373 mCtrlPosY->set( vec.mV[VY] ); 377 mCtrlPosY->set( vec.mV[VY] );
374 mCtrlPosZ->set( vec.mV[VZ] ); 378 mCtrlPosZ->set( vec.mV[VZ] );
379 calcp->setVar(LLCalc::X_POS, vec.mV[VX]);
380 calcp->setVar(LLCalc::Y_POS, vec.mV[VY]);
381 calcp->setVar(LLCalc::Z_POS, vec.mV[VZ]);
375 } 382 }
376 else 383 else
377 { 384 {
378 mCtrlPosX->clear(); 385 mCtrlPosX->clear();
379 mCtrlPosY->clear(); 386 mCtrlPosY->clear();
380 mCtrlPosZ->clear(); 387 mCtrlPosZ->clear();
388 calcp->clearVar(LLCalc::X_POS);
389 calcp->clearVar(LLCalc::Y_POS);
390 calcp->clearVar(LLCalc::Z_POS);
381 } 391 }
382 392
383 393
@@ -392,12 +402,18 @@ void LLPanelObject::getState( )
392 mCtrlScaleX->set( vec.mV[VX] ); 402 mCtrlScaleX->set( vec.mV[VX] );
393 mCtrlScaleY->set( vec.mV[VY] ); 403 mCtrlScaleY->set( vec.mV[VY] );
394 mCtrlScaleZ->set( vec.mV[VZ] ); 404 mCtrlScaleZ->set( vec.mV[VZ] );
405 calcp->setVar(LLCalc::X_SCALE, vec.mV[VX]);
406 calcp->setVar(LLCalc::Y_SCALE, vec.mV[VY]);
407 calcp->setVar(LLCalc::Z_SCALE, vec.mV[VZ]);
395 } 408 }
396 else 409 else
397 { 410 {
398 mCtrlScaleX->clear(); 411 mCtrlScaleX->clear();
399 mCtrlScaleY->clear(); 412 mCtrlScaleY->clear();
400 mCtrlScaleZ->clear(); 413 mCtrlScaleZ->clear();
414 calcp->setVar(LLCalc::X_SCALE, 0.f);
415 calcp->setVar(LLCalc::Y_SCALE, 0.f);
416 calcp->setVar(LLCalc::Z_SCALE, 0.f);
401 } 417 }
402 418
403 mLabelSize->setEnabled( enable_scale ); 419 mLabelSize->setEnabled( enable_scale );
@@ -417,12 +433,18 @@ void LLPanelObject::getState( )
417 mCtrlRotX->set( mCurEulerDegrees.mV[VX] ); 433 mCtrlRotX->set( mCurEulerDegrees.mV[VX] );
418 mCtrlRotY->set( mCurEulerDegrees.mV[VY] ); 434 mCtrlRotY->set( mCurEulerDegrees.mV[VY] );
419 mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] ); 435 mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] );
436 calcp->setVar(LLCalc::X_ROT, mCurEulerDegrees.mV[VX]);
437 calcp->setVar(LLCalc::Y_ROT, mCurEulerDegrees.mV[VY]);
438 calcp->setVar(LLCalc::Z_ROT, mCurEulerDegrees.mV[VZ]);
420 } 439 }
421 else 440 else
422 { 441 {
423 mCtrlRotX->clear(); 442 mCtrlRotX->clear();
424 mCtrlRotY->clear(); 443 mCtrlRotY->clear();
425 mCtrlRotZ->clear(); 444 mCtrlRotZ->clear();
445 calcp->clearVar(LLCalc::X_ROT);
446 calcp->clearVar(LLCalc::Y_ROT);
447 calcp->clearVar(LLCalc::Z_ROT);
426 } 448 }
427 449
428 mLabelRotation->setEnabled( enable_rotate ); 450 mLabelRotation->setEnabled( enable_rotate );
@@ -678,8 +700,9 @@ void LLPanelObject::getState( )
678 F32 end_t = volume_params.getEndT(); 700 F32 end_t = volume_params.getEndT();
679 701
680 // Hollowness 702 // Hollowness
681 F32 hollow = volume_params.getHollow(); 703 F32 hollow = 100.f * volume_params.getHollow();
682 mSpinHollow->set( 100.f * hollow ); 704 mSpinHollow->set( hollow );
705 calcp->setVar(LLCalc::HOLLOW, hollow);
683 706
684 // All hollow objects allow a shape to be selected. 707 // All hollow objects allow a shape to be selected.
685 if (hollow > 0.f) 708 if (hollow > 0.f)
@@ -732,6 +755,10 @@ void LLPanelObject::getState( )
732 mSpinCutEnd ->set( cut_end ); 755 mSpinCutEnd ->set( cut_end );
733 mCtrlPathBegin ->set( adv_cut_begin ); 756 mCtrlPathBegin ->set( adv_cut_begin );
734 mCtrlPathEnd ->set( adv_cut_end ); 757 mCtrlPathEnd ->set( adv_cut_end );
758 calcp->setVar(LLCalc::CUT_BEGIN, cut_begin);
759 calcp->setVar(LLCalc::CUT_END, cut_end);
760 calcp->setVar(LLCalc::PATH_BEGIN, adv_cut_begin);
761 calcp->setVar(LLCalc::PATH_END, adv_cut_end);
735 762
736 // Twist 763 // Twist
737 F32 twist = volume_params.getTwist(); 764 F32 twist = volume_params.getTwist();
@@ -750,18 +777,24 @@ void LLPanelObject::getState( )
750 777
751 mSpinTwist ->set( twist ); 778 mSpinTwist ->set( twist );
752 mSpinTwistBegin ->set( twist_begin ); 779 mSpinTwistBegin ->set( twist_begin );
780 calcp->setVar(LLCalc::TWIST_END, twist);
781 calcp->setVar(LLCalc::TWIST_BEGIN, twist_begin);
753 782
754 // Shear 783 // Shear
755 F32 shear_x = volume_params.getShearX(); 784 F32 shear_x = volume_params.getShearX();
756 F32 shear_y = volume_params.getShearY(); 785 F32 shear_y = volume_params.getShearY();
757 mSpinShearX->set( shear_x ); 786 mSpinShearX->set( shear_x );
758 mSpinShearY->set( shear_y ); 787 mSpinShearY->set( shear_y );
788 calcp->setVar(LLCalc::X_SHEAR, shear_x);
789 calcp->setVar(LLCalc::Y_SHEAR, shear_y);
759 790
760 // Taper 791 // Taper
761 F32 taper_x = volume_params.getTaperX(); 792 F32 taper_x = volume_params.getTaperX();
762 F32 taper_y = volume_params.getTaperY(); 793 F32 taper_y = volume_params.getTaperY();
763 mSpinTaperX->set( taper_x ); 794 mSpinTaperX->set( taper_x );
764 mSpinTaperY->set( taper_y ); 795 mSpinTaperY->set( taper_y );
796 calcp->setVar(LLCalc::X_TAPER, taper_x);
797 calcp->setVar(LLCalc::Y_TAPER, taper_y);
765 798
766 // Radius offset. 799 // Radius offset.
767 F32 radius_offset = volume_params.getRadiusOffset(); 800 F32 radius_offset = volume_params.getRadiusOffset();
@@ -791,10 +824,12 @@ void LLPanelObject::getState( )
791 } 824 }
792 } 825 }
793 mSpinRadiusOffset->set( radius_offset); 826 mSpinRadiusOffset->set( radius_offset);
827 calcp->setVar(LLCalc::RADIUS_OFFSET, radius_offset);
794 828
795 // Revolutions 829 // Revolutions
796 F32 revolutions = volume_params.getRevolutions(); 830 F32 revolutions = volume_params.getRevolutions();
797 mSpinRevolutions->set( revolutions ); 831 mSpinRevolutions->set( revolutions );
832 calcp->setVar(LLCalc::REVOLUTIONS, revolutions);
798 833
799 // Skew 834 // Skew
800 F32 skew = volume_params.getSkew(); 835 F32 skew = volume_params.getSkew();
@@ -819,6 +854,7 @@ void LLPanelObject::getState( )
819 } 854 }
820 } 855 }
821 mSpinSkew->set( skew ); 856 mSpinSkew->set( skew );
857 calcp->setVar(LLCalc::SKEW, skew);
822 } 858 }
823 859
824 // Compute control visibility, label names, and twist range. 860 // Compute control visibility, label names, and twist range.
@@ -924,6 +960,8 @@ void LLPanelObject::getState( )
924 case MI_RING: 960 case MI_RING:
925 mSpinScaleX->set( scale_x ); 961 mSpinScaleX->set( scale_x );
926 mSpinScaleY->set( scale_y ); 962 mSpinScaleY->set( scale_y );
963 calcp->setVar(LLCalc::X_HOLE, scale_x);
964 calcp->setVar(LLCalc::Y_HOLE, scale_y);
927 mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE); 965 mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE);
928 mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X); 966 mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X);
929 mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE); 967 mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE);
@@ -934,6 +972,8 @@ void LLPanelObject::getState( )
934 { 972 {
935 mSpinScaleX->set( 1.f - scale_x ); 973 mSpinScaleX->set( 1.f - scale_x );
936 mSpinScaleY->set( 1.f - scale_y ); 974 mSpinScaleY->set( 1.f - scale_y );
975 calcp->setVar(LLCalc::X_HOLE, 1.f - scale_x);
976 calcp->setVar(LLCalc::Y_HOLE, 1.f - scale_y);
937 mSpinScaleX->setMinValue(-1.f); 977 mSpinScaleX->setMinValue(-1.f);
938 mSpinScaleX->setMaxValue(1.f); 978 mSpinScaleX->setMaxValue(1.f);
939 mSpinScaleY->setMinValue(-1.f); 979 mSpinScaleY->setMinValue(-1.f);
@@ -1148,7 +1188,7 @@ void LLPanelObject::getState( )
1148 mSculptTextureRevert = LLUUID::null; 1188 mSculptTextureRevert = LLUUID::null;
1149 } 1189 }
1150 1190
1151 1191
1152 //---------------------------------------------------------------------------- 1192 //----------------------------------------------------------------------------
1153 1193
1154 mObject = objectp; 1194 mObject = objectp;
@@ -1954,6 +1994,9 @@ void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata )
1954 LLPanelObject* self = (LLPanelObject*) userdata; 1994 LLPanelObject* self = (LLPanelObject*) userdata;
1955 BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; 1995 BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
1956 self->sendRotation(btn_down); 1996 self->sendRotation(btn_down);
1997
1998 // Needed to ensure all rotations are shown consistently in range
1999 self->refresh();
1957} 2000}
1958 2001
1959// static 2002// static
diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml b/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml
index 742da45..05cf101 100644
--- a/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml
+++ b/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml
@@ -614,15 +614,15 @@
614 <spinner bottom_delta="-20" decimal_digits="3" follows="left|top" height="16" 614 <spinner bottom_delta="-20" decimal_digits="3" follows="left|top" height="16"
615 increment="0.01" initial_val="0" label="X" label_width="10" left="10" 615 increment="0.01" initial_val="0" label="X" label_width="10" left="10"
616 max_val="512" min_val="-256" mouse_opaque="true" name="Pos X" 616 max_val="512" min_val="-256" mouse_opaque="true" name="Pos X"
617 text_enabled_color="110, 15, 15, 255" width="87" /> 617 text_enabled_color="110, 15, 15, 255" width="96" />
618 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16" 618 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16"
619 increment="0.01" initial_val="0" label="Y" label_width="10" left="10" 619 increment="0.01" initial_val="0" label="Y" label_width="10" left="10"
620 max_val="512" min_val="-256" mouse_opaque="true" name="Pos Y" 620 max_val="512" min_val="-256" mouse_opaque="true" name="Pos Y"
621 text_enabled_color="0, 100, 40, 255" width="87" /> 621 text_enabled_color="0, 100, 40, 255" width="96" />
622 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16" 622 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16"
623 increment="0.01" initial_val="0" label="Z" label_width="10" left="10" 623 increment="0.01" initial_val="0" label="Z" label_width="10" left="10"
624 max_val="4096" min_val="0" mouse_opaque="true" name="Pos Z" 624 max_val="4096" min_val="0" mouse_opaque="true" name="Pos Z"
625 text_enabled_color="0, 67, 132, 255" width="87" /> 625 text_enabled_color="0, 67, 132, 255" width="96" />
626 <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" 626 <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
627 bottom_delta="-16" drop_shadow_visible="true" follows="left|top" 627 bottom_delta="-16" drop_shadow_visible="true" follows="left|top"
628 font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10" 628 font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10"
@@ -632,15 +632,15 @@
632 <spinner bottom_delta="-20" decimal_digits="3" follows="left|top" height="16" 632 <spinner bottom_delta="-20" decimal_digits="3" follows="left|top" height="16"
633 increment="0.01" initial_val="0" label="X" label_width="10" left="10" 633 increment="0.01" initial_val="0" label="X" label_width="10" left="10"
634 max_val="10" min_val="0.01" mouse_opaque="true" name="Scale X" 634 max_val="10" min_val="0.01" mouse_opaque="true" name="Scale X"
635 text_enabled_color="1, 1, 1, 1" width="87" /> 635 text_enabled_color="1, 1, 1, 1" width="96" />
636 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16" 636 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16"
637 increment="0.01" initial_val="0" label="Y" label_width="10" left="10" 637 increment="0.01" initial_val="0" label="Y" label_width="10" left="10"
638 max_val="10" min_val="0.01" mouse_opaque="true" name="Scale Y" 638 max_val="10" min_val="0.01" mouse_opaque="true" name="Scale Y"
639 text_enabled_color="1, 1, 1, 1" width="87" /> 639 text_enabled_color="1, 1, 1, 1" width="96" />
640 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16" 640 <spinner bottom_delta="-18" decimal_digits="3" follows="left|top" height="16"
641 increment="0.01" initial_val="0" label="Z" label_width="10" left="10" 641 increment="0.01" initial_val="0" label="Z" label_width="10" left="10"
642 max_val="10" min_val="0.01" mouse_opaque="true" name="Scale Z" 642 max_val="10" min_val="0.01" mouse_opaque="true" name="Scale Z"
643 text_enabled_color="1, 1, 1, 1" width="87" /> 643 text_enabled_color="1, 1, 1, 1" width="96" />
644 <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" 644 <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
645 bottom_delta="-16" drop_shadow_visible="true" follows="left|top" 645 bottom_delta="-16" drop_shadow_visible="true" follows="left|top"
646 font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10" 646 font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10"
@@ -650,15 +650,15 @@
650 <spinner bottom_delta="-22" decimal_digits="2" follows="left|top" height="16" 650 <spinner bottom_delta="-22" decimal_digits="2" follows="left|top" height="16"
651 increment="1" initial_val="0" label="X" label_width="10" left="10" 651 increment="1" initial_val="0" label="X" label_width="10" left="10"
652 max_val="9999" min_val="-9999" mouse_opaque="true" name="Rot X" 652 max_val="9999" min_val="-9999" mouse_opaque="true" name="Rot X"
653 text_enabled_color="1, 1, 1, 1" width="87" /> 653 text_enabled_color="1, 1, 1, 1" width="96" />
654 <spinner bottom_delta="-18" decimal_digits="2" follows="left|top" height="16" 654 <spinner bottom_delta="-18" decimal_digits="2" follows="left|top" height="16"
655 increment="1" initial_val="0" label="Y" label_width="10" left="10" 655 increment="1" initial_val="0" label="Y" label_width="10" left="10"
656 max_val="9999" min_val="-9999" mouse_opaque="true" name="Rot Y" 656 max_val="9999" min_val="-9999" mouse_opaque="true" name="Rot Y"
657 text_enabled_color="1, 1, 1, 1" width="87" /> 657 text_enabled_color="1, 1, 1, 1" width="96" />
658 <spinner bottom_delta="-18" decimal_digits="2" follows="left|top" height="16" 658 <spinner bottom_delta="-18" decimal_digits="2" follows="left|top" height="16"
659 increment="1" initial_val="0" label="Z" label_width="10" left="10" 659 increment="1" initial_val="0" label="Z" label_width="10" left="10"
660 max_val="9999" min_val="-9999" mouse_opaque="true" name="Rot Z" 660 max_val="9999" min_val="-9999" mouse_opaque="true" name="Rot Z"
661 text_enabled_color="1, 1, 1, 1" width="87" /> 661 text_enabled_color="1, 1, 1, 1" width="96" />
662 <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false" 662 <text bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
663 bottom_delta="-16" drop_shadow_visible="true" follows="left|top" 663 bottom_delta="-16" drop_shadow_visible="true" follows="left|top"
664 font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10" 664 font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10"