Fix for camera swinging around the long way sometimes. Courtesy Will Monroe.

// Copyright (c) 2011 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(
function() {

    /** DefaultCamera */
    std.graphics.DefaultCamera = system.Class.extend(
        {
            init: function(sim, pres) {
                this._tracking = pres;
                this._mode = 'first';

                this._sim = sim;
                this._sim.onTick(std.core.bind(this.onTick, this));

                this._offset = <0, 0, 0>;

                this._lastPosition = this._tracking.position;
                this._lastOrientation = this._tracking.orientation;

                this.reinit();
            },

            reinit : function() {
                this.setOffset(this._offset);
                this.setMode(this._mode);
            },

            mode : function() {
                 return this._mode;
            },

            setMode : function(mode) {
                this._mode = mode;

                var vis = (mode == 'first' ? false : true);
                this._sim.visible(this._tracking, vis);
            },

            setOffset: function(off) {
                this._offset = off;
            },

            onTick : function(t, dt) {
                var goalPos = this._tracking.position;
                var goalOrient = this._tracking.orientation;

                var pos;
                var orient;

                if (this._mode == 'first') {
                    // In first person mode we are tied tightly to the position of
                    // the object.
                    pos = goalPos;
                    orient = goalOrient;
                }
                else {
                    // In third person mode, the target is offset so we'll be behind and
                    // above ourselves and we need to interpolate to the target.
                    // Offset the goal.
                    // > 1 factor gets us beyond the top of the object
                    goalPos = goalPos + this._offset.mul(this._tracking.scale);
                    // Interpolate from previous positions
                    var toGoal = goalPos-this._lastPosition;
                    var toGoalLen = toGoal.length();
                    if (toGoalLen < 1e-06) {
                        pos = goalPos;
                        orient = goalOrient;
                    } else {
                        var step = util.exp(-dt*2);
                        pos = goalPos - toGoal.div(toGoalLen).mul(toGoalLen*step);
                        if (this._lastOrientation.dot(goalOrient) < 0)
                            this._lastOrientation = this._lastOrientation.neg();
                        orient = (goalOrient.mul(1-step).add(this._lastOrientation.mul(step))).normal();
                    }
                }

                this._sim.setCameraPosition(pos);
                this._sim.setCameraOrientation(orient);

                this._lastPosition = pos;
                this._lastOrientation = orient;
            }

        }
    );

}
)();

// Copyright (c) 2011 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(
function() {

    /** DefaultCamera */
    std.graphics.DefaultCamera = system.Class.extend(
        {
            init: function(sim, pres) {
                this._tracking = pres;
                this._mode = 'first';

                this._sim = sim;
                this._sim.onTick(std.core.bind(this.onTick, this));

                this._offset = <0, 0, 0>;

                this._lastPosition = this._tracking.position;
                this._lastOrientation = this._tracking.orientation;

                this.reinit();
            },

            reinit : function() {
                this.setOffset(this._offset);
                this.setMode(this._mode);
            },

            mode : function() {
                 return this._mode;
            },

            setMode : function(mode) {
                this._mode = mode;

                var vis = (mode == 'first' ? false : true);
                this._sim.visible(this._tracking, vis);
            },

            setOffset: function(off) {
                this._offset = off;
            },

            onTick : function(t, dt) {
                var goalPos = this._tracking.position;
                var goalOrient = this._tracking.orientation;

                var pos;
                var orient;

                if (this._mode == 'first') {
                    // In first person mode we are tied tightly to the position of
                    // the object.
                    pos = goalPos;
                    orient = goalOrient;
                }
                else {
                    // In third person mode, the target is offset so we'll be behind and
                    // above ourselves and we need to interpolate to the target.
                    // Offset the goal.
                    // > 1 factor gets us beyond the top of the object
                    goalPos = goalPos + this._offset.mul(this._tracking.scale);
                    // Interpolate from previous positions
                    var toGoal = goalPos-this._lastPosition;
                    var toGoalLen = toGoal.length();
                    if (toGoalLen < 1e-06) {
                        pos = goalPos;
                        orient = goalOrient;
                    } else {
                        var step = util.exp(-dt*2);
                        pos = goalPos - toGoal.div(toGoalLen).mul(toGoalLen*step);
                        orient = (goalOrient.mul(1-step).add(this._lastOrientation.mul(step))).normal();
                    }
                }

                this._sim.setCameraPosition(pos);
                this._sim.setCameraOrientation(orient);

                this._lastPosition = pos;
                this._lastOrientation = orient;
            }

        }
    );

}
)();


update jobrequeue plugin version

update jobrequeue plugin version

    <org.jenkinsci.plugins.requeuejob.RequeueJobProperty plugin="jobrequeue@@1.1">
      <requeueJob>true</requeueJob>
    </org.jenkinsci.plugins.requeuejob.RequeueJobProperty>

    <org.jenkinsci.plugins.requeuejob.RequeueJobProperty plugin="jobrequeue@@1.0">
      <requeueJob>true</requeueJob>
    </org.jenkinsci.plugins.requeuejob.RequeueJobProperty>


fix parent package path batch syntax.

fix parent package path batch syntax.

REM generated from ros/env-hooks/10.ros.bat.em

REM scrub old ROS bin dirs, to avoid accidentally finding the wrong executables
set _COMMAND=python -c "import os; print(os.pathsep.join([x for x in r'%PATH%'.split(os.pathsep) if not any([d for d in ['cturtle', 'diamondback', 'electric', 'fuerte'] if d in x])]))"
rem Need the delims= line here to ensure that it reads with eol delimiters, not space.
for /f "delims=" %%i in ('%COMMAND%') do set PATH=%%i

set ROS_DISTRO=groovy

REM python function to generate ROS package path based on all parent workspaces (prepends the separator if necessary)
REM do not use EnableDelayedExpansion here, it messes with the != symbols
echo from __future__ import print_function > _parent_package_path.py
echo import os >> _parent_package_path.py
echo env_name = 'CATKIN_WORKSPACES' >> _parent_package_path.py
echo items = os.environ[env_name].split(';') if env_name in os.environ and os.environ[env_name] != '' else [] >> _parent_package_path.py
echo path = '' >> _parent_package_path.py
echo for item in items: >> _parent_package_path.py
echo     path += ':' + (os.path.join(item, 'share') if item.find(':') == -1 else item.split(':')[1]) >> _parent_package_path.py
echo print(path) >> _parent_package_path.py

setlocal EnableDelayedExpansion

set ROS_PACKAGE_PATH_PARENTS=
for /f %%a in ('python _parent_package_path.py') do set ROS_PACKAGE_PATH_PARENTS=!ROS_PACKAGE_PATH_PARENTS!%%a

@[if DEVELSPACE]@
REM env variables in develspace
set ROS_PACKAGE_PATH=@(CMAKE_SOURCE_DIR)!ROS_PACKAGE_PATH_PARENTS!
set ROS_ETC_DIR=@(CATKIN_DEVEL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[else]@
REM env variables in installspace
set ROS_PACKAGE_PATH=@(CMAKE_INSTALL_PREFIX)/share;@(CMAKE_INSTALL_PREFIX)/stacks;%ROS_PACKAGE_PATH_PARENTS%
set ROS_ETC_DIR=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[end if]@

del _parent_package_path.py

REM Make sure these two variables survive local scope
endlocal && set ROS_PACKAGE_PATH=%ROS_PACKAGE_PATH% && set ROS_ETC_DIR=%ROS_ETC_DIR%

REM unset ROS workspace
set ROS_WORKSPACE=
set _COMMAND=

REM generated from ros/env-hooks/10.ros.bat.em

REM scrub old ROS bin dirs, to avoid accidentally finding the wrong executables
set _COMMAND=python -c "import os; print(os.pathsep.join([x for x in r'%PATH%'.split(os.pathsep) if not any([d for d in ['cturtle', 'diamondback', 'electric', 'fuerte'] if d in x])]))"
rem Need the delims= line here to ensure that it reads with eol delimiters, not space.
for /f "delims=" %%i in ('%COMMAND%') do set PATH=%%i

set ROS_DISTRO=groovy

REM python function to generate ROS package path based on all parent workspaces (prepends the separator if necessary)
REM do not use EnableDelayedExpansion here, it messes with the != symbols
echo from __future__ import print_function > _parent_package_path.py
echo import os >> _parent_package_path.py
echo env_name = 'CATKIN_WORKSPACES' >> _parent_package_path.py
echo items = os.environ[env_name].split(';') if env_name in os.environ and os.environ[env_name] != '' else [] >> _parent_package_path.py
echo path = '' >> _parent_package_path.py
echo for item in items: >> _parent_package_path.py
echo     path += ':' + (os.path.join(item, 'share') if item.find(':') == -1 else item.split(':')[1]) >> _parent_package_path.py
echo print(path) >> _parent_package_path.py

setlocal EnableDelayedExpansion

set ROS_PACKAGE_PATH_PARENTS=
for /f %%a in ('python _parent_package_path.py') do set ROS_PACKAGE_PATH_PARENTS=!ROS_PACKAGE_PATH_PARENTS!%%a

@[if DEVELSPACE]@
REM env variables in develspace
set ROS_PACKAGE_PATH=@(CMAKE_SOURCE_DIR)!ROS_PACKAGE_PATH_PARENTS!
set ROS_ETC_DIR=@(CATKIN_DEVEL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[else]@
REM env variables in installspace
set ROS_PACKAGE_PATH=@(CMAKE_INSTALL_PREFIX)/share:@(CMAKE_INSTALL_PREFIX)/stacks$ROS_PACKAGE_PATH_PARENTS
set ROS_ETC_DIR=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[end if]@

del _parent_package_path.py

REM Make sure these two variables survive local scope
endlocal && set ROS_PACKAGE_PATH=%ROS_PACKAGE_PATH% && set ROS_ETC_DIR=%ROS_ETC_DIR%

REM unset ROS workspace
set ROS_WORKSPACE=
set _COMMAND=


Explicit disabling of batch file delayed expansion

REM generated from ros/env-hooks/10.ros.bat.em

REM scrub old ROS bin dirs, to avoid accidentally finding the wrong executables
set _COMMAND=@(PYTHON_EXECUTABLE) -c "import os; print(os.pathsep.join([x for x in r'%PATH%'.split(os.pathsep) if not any([d for d in ['cturtle', 'diamondback', 'electric', 'fuerte'] if d in x])]))"
rem Need the delims= line here to ensure that it reads with eol delimiters, not space.
for /f "delims=" %%i in ('%COMMAND%') do set PATH=%%i

set ROS_DISTRO=indigo

REM python function to generate ROS package path based on all parent workspaces (prepends the separator if necessary)
REM do not use EnableDelayedExpansion here, it messes with the != symbols
setlocal disabledelayedexpansion
echo from __future__ import print_function > _parent_package_path.py
echo import os >> _parent_package_path.py
echo env_name = 'CATKIN_WORKSPACES' >> _parent_package_path.py
echo items = os.environ[env_name].split(';') if env_name in os.environ and os.environ[env_name] != '' else [] >> _parent_package_path.py
echo path = '' >> _parent_package_path.py
echo for item in items: >> _parent_package_path.py
echo     path += ':' + (os.path.join(item, 'share') if item.find(':') == -1 else item.split(':')[1]) >> _parent_package_path.py
echo print(path) >> _parent_package_path.py
endlocal

setlocal EnableDelayedExpansion

set ROS_PACKAGE_PATH_PARENTS=
for /f %%a in ('@(PYTHON_EXECUTABLE) _parent_package_path.py') do set ROS_PACKAGE_PATH_PARENTS=!ROS_PACKAGE_PATH_PARENTS!%%a

@[if DEVELSPACE]@
REM env variables in develspace
set ROS_PACKAGE_PATH=@(CMAKE_SOURCE_DIR)!ROS_PACKAGE_PATH_PARENTS!
set ROS_ETC_DIR=@(CATKIN_DEVEL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[else]@
REM env variables in installspace
set ROS_PACKAGE_PATH=@(CMAKE_INSTALL_PREFIX)/share;@(CMAKE_INSTALL_PREFIX)/stacks;%ROS_PACKAGE_PATH_PARENTS%
set ROS_ETC_DIR=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[end if]@

del _parent_package_path.py

REM Make sure these two variables survive local scope
endlocal && set ROS_PACKAGE_PATH=%ROS_PACKAGE_PATH% && set ROS_ETC_DIR=%ROS_ETC_DIR%

REM unset ROS workspace
set ROS_WORKSPACE=
set _COMMAND=

REM generated from ros/env-hooks/10.ros.bat.em

REM scrub old ROS bin dirs, to avoid accidentally finding the wrong executables
set _COMMAND=@(PYTHON_EXECUTABLE) -c "import os; print(os.pathsep.join([x for x in r'%PATH%'.split(os.pathsep) if not any([d for d in ['cturtle', 'diamondback', 'electric', 'fuerte'] if d in x])]))"
rem Need the delims= line here to ensure that it reads with eol delimiters, not space.
for /f "delims=" %%i in ('%COMMAND%') do set PATH=%%i

set ROS_DISTRO=indigo

REM python function to generate ROS package path based on all parent workspaces (prepends the separator if necessary)
REM do not use EnableDelayedExpansion here, it messes with the != symbols
echo from __future__ import print_function > _parent_package_path.py
echo import os >> _parent_package_path.py
echo env_name = 'CATKIN_WORKSPACES' >> _parent_package_path.py
echo items = os.environ[env_name].split(';') if env_name in os.environ and os.environ[env_name] != '' else [] >> _parent_package_path.py
echo path = '' >> _parent_package_path.py
echo for item in items: >> _parent_package_path.py
echo     path += ':' + (os.path.join(item, 'share') if item.find(':') == -1 else item.split(':')[1]) >> _parent_package_path.py
echo print(path) >> _parent_package_path.py

setlocal EnableDelayedExpansion

set ROS_PACKAGE_PATH_PARENTS=
for /f %%a in ('@(PYTHON_EXECUTABLE) _parent_package_path.py') do set ROS_PACKAGE_PATH_PARENTS=!ROS_PACKAGE_PATH_PARENTS!%%a

@[if DEVELSPACE]@
REM env variables in develspace
set ROS_PACKAGE_PATH=@(CMAKE_SOURCE_DIR)!ROS_PACKAGE_PATH_PARENTS!
set ROS_ETC_DIR=@(CATKIN_DEVEL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[else]@
REM env variables in installspace
set ROS_PACKAGE_PATH=@(CMAKE_INSTALL_PREFIX)/share;@(CMAKE_INSTALL_PREFIX)/stacks;%ROS_PACKAGE_PATH_PARENTS%
set ROS_ETC_DIR=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[end if]@

del _parent_package_path.py

REM Make sure these two variables survive local scope
endlocal && set ROS_PACKAGE_PATH=%ROS_PACKAGE_PATH% && set ROS_ETC_DIR=%ROS_ETC_DIR%

REM unset ROS workspace
set ROS_WORKSPACE=
set _COMMAND=


Make pretty printing only print labels for back-references if they are needed. Patch courtesy of Will Monroe.

/*  Sirikata
 *  pretty.js
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

if (typeof(std) === "undefined") /**@namespace */ std = {};
if (typeof(std.core) === "undefined") /** @namespace */ std.core = {};

/**
 * Converts an object to a string in a 'pretty' format, i.e. so it is
 *  human-readable, multiple lines, and handles indentation. If the
 *  object is not a tree (i.e. it has circular references in it), then
 *  the normal toString version will be returned.  Generally this
 *  should only be used on small, tree-like objects.
 */
std.core.pretty = function(obj) {

    var visited = [];

    // Fast path -- if its not an object or array, we can just do the normal conversion
    if (typeof(obj) !== "object" || obj === null)
        return '' + obj;

    var objectPrettyOverride = function(obj) {
        // If the object overrides pretty printing, just hand back whatever it wants.
        if (typeof(obj.__prettyPrintString__) === "string")
            return obj.__prettyPrintString__;
        else if (typeof(obj.__prettyPrintString__) === "function")
            return obj.__prettyPrintString__();
        else
            return undefined;
    };

    {
        var override = objectPrettyOverride(obj);
        if (override) return override;
    }

    var objectFields = function(obj) {
        if (typeof(obj.__prettyPrintFields__) == "function")
            return obj.__prettyPrintFields__();
        else
            return Object.getOwnPropertyNames(obj);
    };
    var longObject = function(obj) {
        var fields = objectFields(obj);
        if (fields.length > 3)
            return true;

        for(var f in fields)
            if(typeof(obj[fields[f]]) === 'object')
                return true;

        return false;
    };

    var checkVisited = function  (obj)
    {
        for (var s in visited)
        {
            if (visited[s][0] === obj)
            {
                return s;
            }
        }
        return null;
    };

    var output = '';
    var obj_stack = [ {obj: obj, idx: -1} ];
    var indent = '';
    var numPrint = 1;
    while(obj_stack.length != 0) {
        var cur = obj_stack.pop();

        visited.push([cur.obj,numPrint,output.length]);
        ++numPrint;

        // Check if we need to start this object
        if (cur.idx == -1) {
            // Start the object
            output += '{';
            indent += ' ';
            obj_stack.push( {obj: cur.obj, idx: cur.idx+1} );
        }
        else if (cur.idx < objectFields(cur.obj).length) {
            // Setup processing of next child

            // Add a comma and either space or newline as appropriate
            if (cur.idx != 0)
                output += ',';
            if (longObject(cur.obj))
                output += '\n' + indent;
            else
                output += ' ';

            obj_stack.push( {obj: cur.obj, idx: cur.idx+1} );
            // And process this one, possibly triggering recursion
            var key = objectFields(cur.obj)[cur.idx];
            var child = cur.obj[key];
            output += key + ': ';
            if (typeof(child) === "object" && child !== null) {

                //check if we've arleady visited this object.
                var visitedIndex = checkVisited(child);
                if (visitedIndex != null)
                {
					var entry = visited[visitedIndex];
					if(entry[2] != -1)
					{
						var tag = '<#' + entry[1].toString() + '>';
						output = output.slice(0, entry[2]) + tag +
								output.slice(entry[2]);
						for(var i in visited)
							if(visited[i][2] > entry[2])
								visited[i][2] += tag.length;
						visited[visitedIndex][2] = -1;
					}

					output += '<#'+ entry[1].toString() + '>';
                    continue;
                }

                var override = objectPrettyOverride(child);
                if (override)
                    output += override;
                else
                    obj_stack.push( {obj: child, idx: -1} );
            }
            else
                output += child;
        }
        else {
            // Close this object
            indent = indent.substr(1);

            if (longObject(cur.obj))
                output += '\n' + indent;
            else
                output += ' ';

            output += '}';

            // No object stack push, we've finished with this object
        }
    }

    return output;
};

/*  Sirikata
 *  pretty.js
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

if (typeof(std) === "undefined") /**@namespace */ std = {};
if (typeof(std.core) === "undefined") /** @namespace */ std.core = {};

/**
 * Converts an object to a string in a 'pretty' format, i.e. so it is
 *  human-readable, multiple lines, and handles indentation. If the
 *  object is not a tree (i.e. it has circular references in it), then
 *  the normal toString version will be returned.  Generally this
 *  should only be used on small, tree-like objects.
 */
std.core.pretty = function(obj) {

    var visited = [];

    // Fast path -- if its not an object or array, we can just do the normal conversion
    if (typeof(obj) !== "object" || obj === null)
        return '' + obj;

    var objectPrettyOverride = function(obj) {
        // If the object overrides pretty printing, just hand back whatever it wants.
        if (typeof(obj.__prettyPrintString__) === "string")
            return obj.__prettyPrintString__;
        else if (typeof(obj.__prettyPrintString__) === "function")
            return obj.__prettyPrintString__();
        else
            return undefined;
    };

    {
        var override = objectPrettyOverride(obj);
        if (override) return override;
    }

    var objectFields = function(obj) {
        if (typeof(obj.__prettyPrintFields__) == "function")
            return obj.__prettyPrintFields__();
        else
            return Object.getOwnPropertyNames(obj);
    };
    var longObject = function(obj) {
        return (objectFields(obj).length > 3);
    };

    var checkVisited = function  (obj)
    {
        for (var s in visited)
        {
            if (visited[s][0] === obj)
            {
                return visited[s][1];
            }
        }
        return null;
    };

    var output = '';
    var obj_stack = [ {obj: obj, idx: -1} ];
    var indent = '';
    var numPrint = 1;
    while(obj_stack.length != 0) {
        var cur = obj_stack.pop();

        visited.push([cur.obj,numPrint]);
        ++numPrint;

        // Check if we need to start this object
        if (cur.idx == -1) {
            // Start the object
            output += '#'+(numPrint-1) +':{';
            indent += ' ';
            obj_stack.push( {obj: cur.obj, idx: cur.idx+1} );
        }
        else if (cur.idx < objectFields(cur.obj).length) {
            // Setup processing of next child

            // Add a comma and either space or newline as appropriate
            if (cur.idx != 0)
                output += ',';
            if (longObject(cur.obj))
                output += '\n' + indent;
            else
                output += ' ';

            obj_stack.push( {obj: cur.obj, idx: cur.idx+1} );
            // And process this one, possibly triggering recursion
            var key = objectFields(cur.obj)[cur.idx];
            var child = cur.obj[key];
            output += '#' + (numPrint-1) + ':' + key + ': ';
            if (typeof(child) === "object" && child !== null) {

                //check if we've arleady visited this object.
                var visitedIndex = checkVisited(child);
                if (visitedIndex != null)
                {
                    output += indent + '<circ ref. see #'+ visitedIndex.toString() + ' >';
                    continue;
                }

                var override = objectPrettyOverride(child);
                if (override)
                    output += override;
                else
                    obj_stack.push( {obj: child, idx: -1} );
            }
            else
                output += child;
        }
        else {
            // Close this object
            indent = indent.substr(1);

            if (longObject(cur.obj))
                output += '\n' + indent;
            else
                output += ' ';

            output += '}';

            // No object stack push, we've finished with this object
        }
    }

    return output;
};


made it so an unspecified final orientation indicates "dont care where I face at the end" rather than "face where I started facing"

/*  Sirikata
 *  moveAndRotateTo.em
 *
 *  Copyright (c) 2011, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

system.require('moveAndRotate.em');
/** MoveAndRotate gives you intuitive control over moving to a position and
 *  attaining a final rotation. The most common use for this is when you want to
 *  send an object to a particular location with a particular facing when it gets there.
 *  A callback is presented when the object arrives at the destination so further movement
 *  can be queued or an action can take place
 */
std.movement.MoveAndRotateTo = std.movement.MoveAndRotate.extend(
    {
        forceUp:function(upVec) {
            this._force_up=upVec;
        },
        setSpeed:function(speed) {
            this._speed=speed;
        },
        setAngularSpeed:function(angular_speed){
            this._angular_speed=angular_speed;
        },
        setTurningDistance:function(turning_distance){
            this._turning_distance=turning_distance;
        },
        init:function(pres,update_cb, destination, destination_facing, speed, angular_speed, callback){
            this.setSpeed(speed);
            this.setAngularSpeed(angular_speed);
            this._force_up=undefined;
            this._turning_distance=.25;
            std.movement.MoveAndRotate.prototype.init.call(this,pres,update_cb,'rotation');
            if (destination) {
                this.goTo(destination,destination_facing,callback);
            }
        },
        goTo:function(destination,destination_facing, callback) {
            var pos =this._pres.getPosition();
            var forward=destination.sub(pos).normal();

            var goal_orientation=util.Quaternion.fromLookAt(forward,(destination_facing||this._pres.getOrientation()).yAxis());
            if (this._force_up) {
               var tright=this._force_up.cross(forward);
               var tforward=tright.cross(this._force_up).normal();
               goal_orientation=util.Quaternion.fromLookAt(tforward,this._force_up);
            }
            var thus=this;
            var destination_delta=destination.sub(pos);
            var destination_length=destination_delta.length();
            var turning_distance=this._turning_distance;
            destination_delta=destination_delta.scale(turning_distance/destination_length);
            this.goToWaypoint(destination_delta.add(pos),goal_orientation,true, function(){
                 thus.goToWaypoint(destination.add(destination_delta.scale(-.1)),goal_orientation,false,function (){
                                       if (destination_facing) {
                                           thus.goToWaypoint(destination,destination_facing,true,function () {
                                                                 thus.rotateLocalOrientation(new util.Quaternion(0,0,0,1),true);
                                                                 thus.move(new util.Vec3(0,0,0),0,true);
                                                                 callback();
                                     });
                                       } else {
                                           thus.rotateLocalOrientation(new util.Quaternion(0,0,0,1),true);
                                           thus.move(new util.Vec3(0,0,0),0,true);
                                           callback();
                                       }
               });
            });
        },
        abort:function(doClearVelocityAndAngular) {
           if (this._moveTimer) {
               this._moveTimer.clear();
               this._moveTimer=null;
           }
           if (doClearVelocityAndAngular) {
               this.rotateLocalOrientation(new util.Quaternion(0,0,0,1),true);
               this.move(new util.Vec3(0,0,0),0,true);
           }
        },
        goToWaypoint:function(destination,destination_facing,doTurning,callback) {
            this._callback=callback;
            this._destination=destination;
            this._destination_facing=destination_facing;
            var thus=this;
            var pres=this._pres;
            var pos=pres.getPosition();
            var deltapos=this._destination.sub(pos);
            var distance=deltapos.length();
            var inverseOrientation=pres.getOrientation().inverse();
            var rotation=inverseOrientation.mul(this._destination_facing);
            var angle = Math.abs(rotation.angle());
            var time = distance/this._speed;
            if (angle/this._angular_speed>time){
                time = angle/this._angular_speed;
            }
            if (doTurning) {
                this.move(new util.Vec3(0,0,-1),distance/time,true);
            }else {
                var vel=inverseOrientation.mul(deltapos);
                this.move(vel,1.0/time,true);
            }
            this.rotateLocalOrientation(rotation.scale(1.0/time),true);

            this._moveTimer=system.timeout(time,function() {
                           thus._moveTimer=null;
                           pres.setOrientation(destination_facing);
                           if (!doTurning)
                               pres.setPosition(destination);
                           callback.call(thus);
                       });
        }
    }
);

/*  Sirikata
 *  moveAndRotateTo.em
 *
 *  Copyright (c) 2011, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

system.require('moveAndRotate.em');
/** MoveAndRotate gives you intuitive control over moving to a position and
 *  attaining a final rotation. The most common use for this is when you want to
 *  send an object to a particular location with a particular facing when it gets there.
 *  A callback is presented when the object arrives at the destination so further movement
 *  can be queued or an action can take place
 */
std.movement.MoveAndRotateTo = std.movement.MoveAndRotate.extend(
    {
        forceUp:function(upVec) {
            this._force_up=upVec;
        },
        setSpeed:function(speed) {
            this._speed=speed;
        },
        setAngularSpeed:function(angular_speed){
            this._angular_speed=angular_speed;
        },
        setTurningDistance:function(turning_distance){
            this._turning_distance=turning_distance;
        },
        init:function(pres,update_cb, destination, destination_facing, speed, angular_speed, callback){
            this.setSpeed(speed);
            this.setAngularSpeed(angular_speed);
            this._force_up=undefined;
            this._turning_distance=.25;
            std.movement.MoveAndRotate.prototype.init.call(this,pres,update_cb,'rotation');
            if (destination) {
                this.goTo(destination,destination_facing,callback);
            }
        },
        goTo:function(destination,destination_facing, callback) {
            var pos =this._pres.getPosition();
            var forward=destination.sub(pos).normal();
            destination_facing=destination_facing||this._pres.getOrientation();
            var goal_orientation=util.Quaternion.fromLookAt(forward,destination_facing.yAxis());
            if (this._force_up) {
               var tright=this._force_up.cross(forward);
               var tforward=tright.cross(this._force_up).normal();
               goal_orientation=util.Quaternion.fromLookAt(tforward,this._force_up);
            }
            var thus=this;
            var destination_delta=destination.sub(pos);
            var destination_length=destination_delta.length();
            var turning_distance=this._turning_distance;
            destination_delta=destination_delta.scale(turning_distance/destination_length);
            this.goToWaypoint(destination_delta.add(pos),goal_orientation,true, function(){
                 thus.goToWaypoint(destination.add(destination_delta.scale(-.1)),goal_orientation,false,function (){
                   thus.goToWaypoint(destination,(destination_facing||this._pres.orientation()),true,function () {
                                         thus.rotateLocalOrientation(new util.Quaternion(0,0,0,1),true);
                                         thus.move(new util.Vec3(0,0,0),0,true);
                                         callback();
                                     });
               });
            });
        },
        abort:function(doClearVelocityAndAngular) {
           if (this._moveTimer) {
               this._moveTimer.clear();
               this._moveTimer=null;
           }
           if (doClearVelocityAndAngular) {
               this.rotateLocalOrientation(new util.Quaternion(0,0,0,1),true);
               this.move(new util.Vec3(0,0,0),0,true);
           }
        },
        goToWaypoint:function(destination,destination_facing,doTurning,callback) {
            this._callback=callback;
            this._destination=destination;
            this._destination_facing=destination_facing;
            var thus=this;
            var pres=this._pres;
            var pos=pres.getPosition();
            var deltapos=this._destination.sub(pos);
            var distance=deltapos.length();
            var inverseOrientation=pres.getOrientation().inverse();
            var rotation=inverseOrientation.mul(this._destination_facing);
            var angle = Math.abs(rotation.angle());
            var time = distance/this._speed;
            if (angle/this._angular_speed>time){
                time = angle/this._angular_speed;
            }
            if (doTurning) {
                this.move(new util.Vec3(0,0,-1),distance/time,true);
            }else {
                var vel=inverseOrientation.mul(deltapos);
                this.move(vel,1.0/time,true);
            }
            this.rotateLocalOrientation(rotation.scale(1.0/time),true);

            this._moveTimer=system.timeout(time,function() {
                           thus._moveTimer=null;
                           pres.setOrientation(destination_facing);
                           if (!doTurning)
                               pres.setPosition(destination);
                           callback.call(thus);
                       });
        }
    }
);


sdxo#2692: Whoo .. the ghostly-appearance was happening due to "set_sensitive(False)" of listview, introduced as part of multi-select feature. Therefore, to restore sanity, the theme had to be changed for this widget.


fix url and make operation atomic

fix url and make operation atomic

@[if os_name == 'ubuntu' and os_code_name in ['trusty', 'utopic', 'vivid'] or os_name == 'debian' and os_code_name in ['jessie']]@
@# We need ccache 3.2 or higher: https://github.com/ros-infrastructure/buildfarm_deployment/issues/113
RUN python3 -u /tmp/wrapper_scripts/apt-get.py update-and-install -q -y curl gcc make
RUN curl https://www.samba.org/ftp/ccache/ccache-3.2.4.tar.gz -o /tmp/ccache.tar.gz && tar -xf /tmp/ccache.tar.gz --directory /tmp
RUN mkdir -p /usr/lib/ccache
RUN cd /tmp/ccache-3.2.4 && ./configure && make && make install
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/c++
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/cc
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/g++
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/gcc
@[else]@
RUN python3 -u /tmp/wrapper_scripts/apt-get.py update-and-install -q -y ccache
@[end if]@

@[if os_name == 'ubuntu' and os_code_name in ['trusty', 'utopic', 'vivid'] or os_name == 'debian' and os_code_name in ['jessie']]@
@# We need ccache 3.2 or higher: https://github.com/ros-infrastructure/buildfarm_deployment/issues/113
RUN python3 -u /tmp/wrapper_scripts/apt-get.py update-and-install -q -y curl gcc make
RUN curl https://www.samba.org/ftp/ccache/ccache-3.2.4.tar.bz2 -o /tmp/ccache.tar.gz
RUN tar -xf /tmp/ccache.tar.gz --directory /tmp
RUN mkdir -p /usr/lib/ccache
RUN cd /tmp/ccache-3.2.4 && ./configure && make && make install
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/c++
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/cc
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/g++
RUN ln -s /usr/local/bin/ccache /usr/lib/ccache/gcc
@[else]@
RUN python3 -u /tmp/wrapper_scripts/apt-get.py update-and-install -q -y ccache
@[end if]@


3.20:  Fix combobox arrow not rendering

3.20:  Fix combobox arrow not rendering

${
import os
import math

gtk_major, gtk_minor, gtk_patch = map(int, gtk.split('.'))
treeview_pseudo_element = gtk_major >= 3 and gtk_minor >= 16

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if scaling == "100":
    xo = True
    line_width = 2.0        # 2.25px, rounded down
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    icon_base = 11
    bullet_size = 9.5
    font_height = 24
    default_padding = 6
    toolbutton_padding = 10
    radio_size = 26
    scale_trough_margin = 8
else: # About 72% of the XO size, adjusted so that eg. toolbuttons work
    xo = False
    line_width = 2.0            # 1.62 rounded up
    thick_line_width = 3.0      # 2.52
    subcell_size = 11           # 10.8
    icon_base = 8               # 7.92
    bullet_size = 6.5           # 6.84
    # This is a guess on the font size (Sans 10 at 96 DPI)
    font_height = 17
    default_padding = 4         # 4.32
    toolbutton_padding = 7      # 7.68
    radio_size = 18             # 18.72
    scale_trough_margin = 6     # 5.76

scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

icon_small = icon_base * 3
icon_large = icon_base * 5

disabled_opacity = 0.5

}

* {
    -sugar-focus-line: @white;

    /* 0.05 works good for both the sugar and sugar-xo themes */
    -GtkWidget-cursor-aspect-ratio: 0.05;

    -GtkWidget-wide-separators: true;
    -GtkWidget-separator-height: $thickness;
    -GtkWidget-separator-width: $thickness;

    -GtkWidget-scroll-arrow-hlength: $subcell_size;
    -GtkWidget-scroll-arrow-vlength: $subcell_size;

    -GtkRange-activate-slider: 1;

    -GtkScrolledWindow-scrollbar-spacing: 0;

    -GtkExpander-expander-size: $font_height;
    -GtkExpander-expander-spacing: 2;

    -GtkTreeView-expander-size: $font_height;

    -GtkArrow-arrow-size: 1.0;

    -GtkToolbar-space-size: $(2*subcell_size);

    -GtkProgressBar-min-horizontal-bar-height: $subcell_size;
    -GtkProgressBar-min-vertical-bar-width: $subcell_size;

    -GtkCheckButton-indicator-size: $radio_size;
    -GtkCheckButton-indicator-spacing: 3;

    -GtkWidget-text-handle-width: 110px;
    -GtkWidget-text-handle-height: 110px;
}

*:disabled {
    color: @panel_grey;
}

/* Backgrounds and windows */

window {
    background: @panel_grey;
    color: @black;
}

dialog {
    background: @black;
    color: @white;
}

introwindow {
    background: @white;
    color: @black;
}

label, label:disabled {
    background: transparent;
}

/* Buttons */

button {
    ${ border = max(0, my_ceil((3*subcell_size/2.0 - icon_small / 2.0))) }
    padding: $(border)px $(border)px $(border)px $(border)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    border-radius: $(2*subcell_size)px;
    background: @button_grey;
    color: @white;
}

button:focus {
    border-color: @white;
    color: @white;
}

button:active {
    background: @white;
    color: @black;
}

button:disabled {
    background: transparent;
}

button:active:focus {
    color: @black;
    border-color: @button_grey;
}

/* Linked boxes (eg. combobox entries) */

box.linked *:not(:first-child):not(:last-child) {
    border-radius: 0;
}

box.linked *:first-child:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

box.linked *:not(:first-child):last-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* Spin buttons */

spinbutton button {
    background: @button_grey;
    border-style: solid;
    border-radius: 0;
}

spinbutton.horizontal button:last-child {
    border-radius: 0 $(2*subcell_size)px $(2*subcell_size)px 0;
}

spinbutton.vertical button:first-child {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px 0 0;
    border-width: $(thickness)px $(thickness)px 0 $(thickness)px;
    border-style: solid;
}

spinbutton.vertical button:last-child {
    border-radius: 0 0 $(2*subcell_size)px $(2*subcell_size)px;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

spinbutton button:active {
    background: @black;
}

spinbutton button:disabled {
    background: @selection_grey;
}

/* Toggle buttons */

button:checked {
    background: @white;
    color: @black;
}

/* Entries and views (textview, treeview) */

.view,
textview text {  /* Setting a textview to background white makes it black,
                    unless you only style the text css node */
    border-width: 0px;
    border-style: none;
    border-radius: 0px;
    padding: 0px;
    background: @white;
    color: @black;
}

treeview header button,
treeview header button:hover:active {
    border-radius: 0px;
    background: @button_grey;
    border-width: 0px;
    color: @white;
}

/* FIXME: treeview row css nodes aren't a thing

    $[if treeview_pseudo_element] GtkTreeView row:even
    $[else] GtkTreeView row:nth-child(even)
    $[end if] {
        background: @row_even;
    }

    $[if treeview_pseudo_element] GtkTreeView row:odd
    $[else] GtkTreeView row:nth-child(odd)
    $[end if] {
        background: @row_odd;
    }
*/

entry {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    border-color: @text_field_grey;
    border-style: solid;
    background: @text_field_grey;
    color: @black;
    ${ entry_ythickness = my_ceil(0.2 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    ${ entry_xthickness = my_ceil(0.32 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    padding: $(2 * max(my_ceil((3*subcell_size - font_height - entry_ythickness*2)/2.0),0))px $(2 * max(subcell_size - entry_xthickness, 0))px $(2 * max(my_floor((3*subcell_size - font_height - entry_ythickness*2)/2.0), 0))px $(2 * max(subcell_size - entry_xthickness, 0))px;
}

entry image {
    /* Default padding is too large and causes toolbar height expansion */
    margin: $(default_padding-1)px;
}

toolitem entry {
    margin: $(subcell_size)px;
}

entry progressbar {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    background: @selection_grey;
}

entry:focus {
    background: @white;
}

toolbar entry:focus {
    border-color: @white;
}

entry:disabled {
    background: @button_grey;
    border-color: @button_grey;
}

treeview:selected {
    background: @panel_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    background: @selection_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    border-color: @selection_grey;
}

selection {
    background: @selected_bg_color;
    color: @selected_fg_color;
}

/* Frames */

frame {
    border-style: solid;
    border-color: @selection_grey;
    border-width: $(thickness)px;
    border-radius: 0;
    padding: $(default_padding)px;
}

frame.journal-preview-box {
    border-color: @button_grey;
}

/* Combo boxes */

combobox {
    color: @white;
}

combobox button.combo arrow {
    -gtk-icon-source: -gtk-icontheme('control-popup-arrow');
    -gtk-icon-transform: scale(0.3);
    min-width: $(subcell_size)px;
    min-height: $(subcell_size)px;
}

/* What does this do?
    combobox .menu.button {
        border-color: transparent;
        border-radius: 0px;
        border-style: none;
        background: transparent;
        color: @white;
    }
*/

combobox menu {
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

/* Notebooks */

notebook {
    background: @selection_grey;
    color: @black;
    padding: 0px;
    -GtkNotebook-tab-overlap: -2;
    -GtkNotebook-tab-curvature: $default_padding;
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

notebook arrow {
    color: @white;
}

notebook tab {
    background: @selection_grey;
}

/* Setting white color to the tab labels using only the previous rule */
/* doesn't work, so we have to set white color to the GtkLabel, and make */
/* sure the buttons get black color in the next two rules: */
notebook tab label {
    color: @white;
    padding: $(subcell_size)px 0;
}

notebook tab button label {
    color: @black;
}

notebook tab:checked {
    background: @toolbar_grey;
}

notebook tab button {
    border-radius: $(toolbutton_padding)px;
}

/* Browse Widgets */

BrowseSearchWindow treeview {
    background: @black;
    color: @white;
    border-color: @button_grey;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

/* Control panel */

cpanelsectionview {
    background: @white;
    color: @black;
}

/* TODO:  this should only effect the control panel */
controlpanel image:disabled {
    opacity: $(disabled_opacity);
}

/* Alert */

alert {
    background: @black;
    color: @white;
}

alert *:disabled {
    background: @black;
}

button timeouticon label,
button timeouticon label:hover {
    background: @white;
    color: @button_grey;
    border-radius: $(2 * subcell_size)px;
}

button:active timeouticon label {
    background: @toolbar_grey;
    color: @white;
}

/* Tray */

htray, vtray {
    background: @toolbar_grey;
}

htray * , vtray * { background: @toolbar_grey;}

/* Menus and palettes */

palette,
popover {
    border: $(thickness)px solid @button_grey;
    background: @black;
    color: @white;
}

palette .view {
    color: @black;
}

SugarPaletteMenuWidget {
    background: @black;
}

SugarPaletteMenuWidget * {
    color: @white;
}

SugarPaletteWindow SugarGroupBox {
    background: @toolbar_grey;
    color: @white;
}

SugarPaletteWindow SugarGroupBox *:disabled {
    background: @toolbar_grey;
}

menu {
    background: @black;
    color: @white;

    -GtkMenu-scroll-arrow-vlength: $(my_floor(subcell_size/0.7 + 2*thickness));
    /* This means the outline of the submenu overlaps with a palette.
     * However in the case of two normal menus, they are next to each other.
     * It is not possible to be smarter about this, because the style comes from
     * the submenu. */
    -GtkMenu-horizontal-offset :  -$(line_width)px;
    -GtkMenu-vertical-offset   : 0;

    padding: 0px;

    border: $(thickness)px solid @button_grey;
}

menuitem {
    padding: $(subcell_size)px $((subcell_size * 3 - font_height) / 2)px;
}

menuitem:hover,
menuitem:hover {
    background: @button_grey;
}

menuitem separator {
    padding: 0;
}

tooltip {
    background: @black;
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @button_grey;
}

tooltip * {
    color: @white;
}

/* Scrollbars */

scrollbar {
    -GtkRange-slider-width: $(subcell_size + 2*thickness);
    -GtkRange-trough-border: 0;
    -GtkRange-stepper-size: 0;
    -GtkScrollbar-min-slider-length: $(3*subcell_size);
    -GtkScrollbar-has-forward-stepper: 0;
    -GtkScrollbar-has-backward-stepper: 0;
    -GtkScrollbar-has-secondary-forward-stepper: 0;
    -GtkScrollbar-has-secondary-backward-stepper: 0;
}

scrollbar trough {
    background: @button_grey;
    border-width: 0px;
}

scrollbar slider {
    background: @white;
    border-radius: $(2*subcell_size)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
}

scrollbar slider:active {
    background: @text_field_grey;
}

/* Progress bars */

progressbar progress {
    background: @white;
    border-color: @button_grey;
    border-radius: $(subcell_size)px;
    border-style: solid;
    border-width: $(thickness)px;
}

progressbar trough {
    background: @selection_grey;
    border-style: solid;
    border-radius: $(subcell_size)px;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

toolbar progressbar trough,
palette progressbar trough {
    background: @black;
}

/* Separators */

separator {
    /*border-top: $(thickness)px solid @button_grey;*/
    background-color: @button_grey;
}

/* Tool buttons */

toolbar,
toolbarbox {
    padding: 0;
    background: @toolbar_grey;
    color: @white;
}

/* FIXME: I needed to add the margin in the gtk3.20 port, but that wasn't
          there in the code before.  I ended up having to reduce the border
          to 2px */
toolbutton button,
filtertoolbutton button {
    border-style: none;
    background: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding - default_padding)px;
    margin: $(default_padding)px;
}

toolbutton button #gtk-toolbar-arrow {
    padding: 0 $(subcell_size + default_padding)px;
}

toolbutton button:disabled {
    opacity: $(disabled_opacity);
}

toolbutton button:hover {
    padding: $(toolbutton_padding - 2 - default_padding)px;
    border-width: 2px;
    border-style: solid;
    background-clip: padding-box;
}

toolbutton button:hover:not(:checked),
toolbutton button:hover:not(:checked) * {
    background: @black;
}

toolbutton button.radio:checked,
toolbutton button.radio:checked * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

toolbutton button.radio:checked:hover,
toolbutton button.radio:checked:hover * {
    background: @button_grey;
    border-color: @button_grey;
}

toolbutton button:active,
toolbutton button:active * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

palette scrolledwindow {
    background: @black;
}

toolbar combobox button {
    border-radius: $(2*subcell_size)px;
}

/* Scales */

scale {
    -GtkScale-slider-length: $scale_slider_width;
    -GtkRange-slider-width: $scale_slider_width;
}

scale highlight {
    background: @white;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

scale trough {
    background: @button_grey;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
    margin: $(scale_trough_margin)px 0;
}

scale.vertical trough {
    margin: 0 $(scale_trough_margin)px;
}

scale trough:focus {
    border-color: @white;
}

scale trough,
scale highlight {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px;
}

scale slider,
scale slider:active {
    background: transparent;
}

scale slider {
    background-image: url("assets/scale-slider.svg");
}

scale slider:active {
    background-image: url("assets/scale-slider-active.svg");
}

/* Radio and check buttons */

check:hover {
    background: alpha(@theme_base_color, 0.0);
}

toolbar check,
palette check {
    color: @theme_base_color;
    border: 1px solid @theme_base_color;
}

radio,
radio row:selected,
radio row:selected:focus {
    -gtk-icon-source: url("assets/radio.svg");
    background: alpha(@theme_base_color, 0.0);
}

radio:selected,
radio:selected row:selected,
radio:selected row:selected:focus {
    -gtk-icon-source: url("assets/radio-selected.svg");
}

radio:active,
radio row:selected:active,
radio row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active.svg");
}

radio:checked,
radio row:selected:checked,
radio row:selected:focus:checked {
   -gtk-icon-source: url("assets/radio-active.svg");
}

radio:active:selected,
radio:selected row:selected:active,
radio:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

radio:checked:selected,
radio:selected row:selected:checked,
radio:selected row:selected:focus:checked {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

check,
check row:selected,
check row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked.svg");
    background: alpha(@theme_base_color, 0.0);
}

check:selected,
check:selected row:selected,
check:selected row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked-selected.svg");
}

check:active,
check row:selected:active,
check row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:checked,
check row:selected:checked,
check row:selected:focus:checked {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:active:selected,
check:selected row:selected:active,
check:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

check:checked:selected,
check:selected row:selected:checked,
check:selected row:selected:focus:checked {
    background-image: url("assets/checkbox-checked-selected.svg");
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

/* Tool items */

toolitem {
    /* arrow in the toolbarbox */
    color: @white;
}

.palette-down,
.toolbar-down {
    /* outline of the toolbarbutton when palette is expanded */
    border-style: solid;
    border-width: 2px;
    border-color: @button_grey;
}

/* GtkImage */

image {
    background: transparent;
}

/* Sugar Frame Window */

framewindow {
    background: @toolbar_grey;
}

/* Sugar Canvas icon */

canvasicon {
    border-color: transparent;
    border-radius: $(4 * thickness)px;
    border-width: 2px;
    border-style: solid;
    background: transparent;
}

canvasicon:hover {
    border-color: @zoom_views_prelight;
    background: @zoom_views_prelight;
}

canvasicon.toggle-press {
    border-color: @zoom_views_active;
    background: @zoom_views_active;
}

/* Sugar CellRenderer Icons */

.cell.sugar-icon-cell {
    background: transparent;
    border-radius: $(4 * thickness)px;
    border-color: @white;
    border-width: $(thickness)px;
    border-style: solid;
}

.cell.sugar-icon-cell:hover {
    background: @zoom_views_prelight;
}

.cell.sugar-icon-cell:active {
    background: @zoom_views_active;
}

/* CellRendererProgress */

.cell.progressbar, .cell.trough {
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @selection_grey;
    border-radius: $(2*subcell_size)px;
}

.cell.progressbar {
    background: @white;
}

.cell.trough {
    background: @text_field_grey;
}

/* Text cursor handles */

cursor-handle.top,
cursor-handle.bottom {
    background: transparent;
    border-radius: 10px;
    border-width: $(thickness)px;
    border-color: @panel_grey;
    border-style: solid;
}

cursor-handle.bottom {
    -gtk-icon-source: url("assets/cursor-handle-bottom.svg");
}

cursor-handle.top {
    -gtk-icon-source: url("assets/cursor-handle-top.svg");
}

cursor-handle.insertion-cursor {
    -gtk-icon-source: url("assets/cursor-handle-insertion.svg");
}

/* Application specific properties */

EvView {
    background: @panel_grey;
}

EvView:selected,
ApDocView:selected {
    background: @selection_grey;
}

${
import os
import math

gtk_major, gtk_minor, gtk_patch = map(int, gtk.split('.'))
treeview_pseudo_element = gtk_major >= 3 and gtk_minor >= 16

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if scaling == "100":
    xo = True
    line_width = 2.0        # 2.25px, rounded down
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    icon_base = 11
    bullet_size = 9.5
    font_height = 24
    default_padding = 6
    toolbutton_padding = 10
    radio_size = 26
    scale_trough_margin = 8
else: # About 72% of the XO size, adjusted so that eg. toolbuttons work
    xo = False
    line_width = 2.0            # 1.62 rounded up
    thick_line_width = 3.0      # 2.52
    subcell_size = 11           # 10.8
    icon_base = 8               # 7.92
    bullet_size = 6.5           # 6.84
    # This is a guess on the font size (Sans 10 at 96 DPI)
    font_height = 17
    default_padding = 4         # 4.32
    toolbutton_padding = 7      # 7.68
    radio_size = 18             # 18.72
    scale_trough_margin = 6     # 5.76

scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

icon_small = icon_base * 3
icon_large = icon_base * 5

disabled_opacity = 0.5

}

* {
    -sugar-focus-line: @white;

    /* 0.05 works good for both the sugar and sugar-xo themes */
    -GtkWidget-cursor-aspect-ratio: 0.05;

    -GtkWidget-wide-separators: true;
    -GtkWidget-separator-height: $thickness;
    -GtkWidget-separator-width: $thickness;

    -GtkWidget-scroll-arrow-hlength: $subcell_size;
    -GtkWidget-scroll-arrow-vlength: $subcell_size;

    -GtkRange-activate-slider: 1;

    -GtkScrolledWindow-scrollbar-spacing: 0;

    -GtkExpander-expander-size: $font_height;
    -GtkExpander-expander-spacing: 2;

    -GtkTreeView-expander-size: $font_height;

    -GtkArrow-arrow-size: 1.0;

    -GtkToolbar-space-size: $(2*subcell_size);

    -GtkProgressBar-min-horizontal-bar-height: $subcell_size;
    -GtkProgressBar-min-vertical-bar-width: $subcell_size;

    -GtkCheckButton-indicator-size: $radio_size;
    -GtkCheckButton-indicator-spacing: 3;

    -GtkWidget-text-handle-width: 110px;
    -GtkWidget-text-handle-height: 110px;
}

*:disabled {
    color: @panel_grey;
}

/* Backgrounds and windows */

window {
    background: @panel_grey;
    color: @black;
}

dialog {
    background: @black;
    color: @white;
}

introwindow {
    background: @white;
    color: @black;
}

label, label:disabled {
    background: transparent;
}

/* Buttons */

button {
    ${ border = max(0, my_ceil((3*subcell_size/2.0 - icon_small / 2.0))) }
    padding: $(border)px $(border)px $(border)px $(border)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    border-radius: $(2*subcell_size)px;
    background: @button_grey;
    color: @white;
}

button:focus {
    border-color: @white;
    color: @white;
}

button:active {
    background: @white;
    color: @black;
}

button:disabled {
    background: transparent;
}

button:active:focus {
    color: @black;
    border-color: @button_grey;
}

/* Linked boxes (eg. combobox entries) */

box.linked *:not(:first-child):not(:last-child) {
    border-radius: 0;
}

box.linked *:first-child:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

box.linked *:not(:first-child):last-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* Spin buttons */

spinbutton button {
    background: @button_grey;
    border-style: solid;
    border-radius: 0;
}

spinbutton.horizontal button:last-child {
    border-radius: 0 $(2*subcell_size)px $(2*subcell_size)px 0;
}

spinbutton.vertical button:first-child {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px 0 0;
    border-width: $(thickness)px $(thickness)px 0 $(thickness)px;
    border-style: solid;
}

spinbutton.vertical button:last-child {
    border-radius: 0 0 $(2*subcell_size)px $(2*subcell_size)px;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

spinbutton button:active {
    background: @black;
}

spinbutton button:disabled {
    background: @selection_grey;
}

/* Toggle buttons */

button:checked {
    background: @white;
    color: @black;
}

/* Entries and views (textview, treeview) */

.view,
textview text {  /* Setting a textview to background white makes it black,
                    unless you only style the text css node */
    border-width: 0px;
    border-style: none;
    border-radius: 0px;
    padding: 0px;
    background: @white;
    color: @black;
}

treeview header button,
treeview header button:hover:active {
    border-radius: 0px;
    background: @button_grey;
    border-width: 0px;
    color: @white;
}

/* FIXME: treeview row css nodes aren't a thing

    $[if treeview_pseudo_element] GtkTreeView row:even
    $[else] GtkTreeView row:nth-child(even)
    $[end if] {
        background: @row_even;
    }

    $[if treeview_pseudo_element] GtkTreeView row:odd
    $[else] GtkTreeView row:nth-child(odd)
    $[end if] {
        background: @row_odd;
    }
*/

entry {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    border-color: @text_field_grey;
    border-style: solid;
    background: @text_field_grey;
    color: @black;
    ${ entry_ythickness = my_ceil(0.2 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    ${ entry_xthickness = my_ceil(0.32 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    padding: $(2 * max(my_ceil((3*subcell_size - font_height - entry_ythickness*2)/2.0),0))px $(2 * max(subcell_size - entry_xthickness, 0))px $(2 * max(my_floor((3*subcell_size - font_height - entry_ythickness*2)/2.0), 0))px $(2 * max(subcell_size - entry_xthickness, 0))px;
}

entry image {
    /* Default padding is too large and causes toolbar height expansion */
    margin: $(default_padding-1)px;
}

toolitem entry {
    margin: $(subcell_size)px;
}

entry progressbar {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    background: @selection_grey;
}

entry:focus {
    background: @white;
}

toolbar entry:focus {
    border-color: @white;
}

entry:disabled {
    background: @button_grey;
    border-color: @button_grey;
}

treeview:selected {
    background: @panel_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    background: @selection_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    border-color: @selection_grey;
}

selection {
    background: @selected_bg_color;
    color: @selected_fg_color;
}

/* Frames */

frame {
    border-style: solid;
    border-color: @selection_grey;
    border-width: $(thickness)px;
    border-radius: 0;
    padding: $(default_padding)px;
}

frame.journal-preview-box {
    border-color: @button_grey;
}

/* Combo boxes */

combobox {
    color: @white;
}

/* What does this do?
    combobox .menu.button {
        border-color: transparent;
        border-radius: 0px;
        border-style: none;
        background: transparent;
        color: @white;
    }
*/

combobox menu {
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

/* Notebooks */

notebook {
    background: @selection_grey;
    color: @black;
    padding: 0px;
    -GtkNotebook-tab-overlap: -2;
    -GtkNotebook-tab-curvature: $default_padding;
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

notebook arrow {
    color: @white;
}

notebook tab {
    background: @selection_grey;
}

/* Setting white color to the tab labels using only the previous rule */
/* doesn't work, so we have to set white color to the GtkLabel, and make */
/* sure the buttons get black color in the next two rules: */
notebook tab label {
    color: @white;
    padding: $(subcell_size)px 0;
}

notebook tab button label {
    color: @black;
}

notebook tab:checked {
    background: @toolbar_grey;
}

notebook tab button {
    border-radius: $(toolbutton_padding)px;
}

/* Browse Widgets */

BrowseSearchWindow treeview {
    background: @black;
    color: @white;
    border-color: @button_grey;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

/* Control panel */

cpanelsectionview {
    background: @white;
    color: @black;
}

/* TODO:  this should only effect the control panel */
controlpanel image:disabled {
    opacity: $(disabled_opacity);
}

/* Alert */

alert {
    background: @black;
    color: @white;
}

alert *:disabled {
    background: @black;
}

button timeouticon label,
button timeouticon label:hover {
    background: @white;
    color: @button_grey;
    border-radius: $(2 * subcell_size)px;
}

button:active timeouticon label {
    background: @toolbar_grey;
    color: @white;
}

/* Tray */

htray, vtray {
    background: @toolbar_grey;
}

htray * , vtray * { background: @toolbar_grey;}

/* Menus and palettes */

palette,
popover {
    border: $(thickness)px solid @button_grey;
    background: @black;
    color: @white;
}

palette .view {
    color: @black;
}

SugarPaletteMenuWidget {
    background: @black;
}

SugarPaletteMenuWidget * {
    color: @white;
}

SugarPaletteWindow SugarGroupBox {
    background: @toolbar_grey;
    color: @white;
}

SugarPaletteWindow SugarGroupBox *:disabled {
    background: @toolbar_grey;
}

menu {
    background: @black;
    color: @white;

    -GtkMenu-scroll-arrow-vlength: $(my_floor(subcell_size/0.7 + 2*thickness));
    /* This means the outline of the submenu overlaps with a palette.
     * However in the case of two normal menus, they are next to each other.
     * It is not possible to be smarter about this, because the style comes from
     * the submenu. */
    -GtkMenu-horizontal-offset :  -$(line_width)px;
    -GtkMenu-vertical-offset   : 0;

    padding: 0px;

    border: $(thickness)px solid @button_grey;
}

menuitem {
    padding: $(subcell_size)px $((subcell_size * 3 - font_height) / 2)px;
}

menuitem:hover,
menuitem:hover {
    background: @button_grey;
}

menuitem separator {
    padding: 0;
}

tooltip {
    background: @black;
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @button_grey;
}

tooltip * {
    color: @white;
}

/* Scrollbars */

scrollbar {
    -GtkRange-slider-width: $(subcell_size + 2*thickness);
    -GtkRange-trough-border: 0;
    -GtkRange-stepper-size: 0;
    -GtkScrollbar-min-slider-length: $(3*subcell_size);
    -GtkScrollbar-has-forward-stepper: 0;
    -GtkScrollbar-has-backward-stepper: 0;
    -GtkScrollbar-has-secondary-forward-stepper: 0;
    -GtkScrollbar-has-secondary-backward-stepper: 0;
}

scrollbar trough {
    background: @button_grey;
    border-width: 0px;
}

scrollbar slider {
    background: @white;
    border-radius: $(2*subcell_size)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
}

scrollbar slider:active {
    background: @text_field_grey;
}

/* Progress bars */

progressbar progress {
    background: @white;
    border-color: @button_grey;
    border-radius: $(subcell_size)px;
    border-style: solid;
    border-width: $(thickness)px;
}

progressbar trough {
    background: @selection_grey;
    border-style: solid;
    border-radius: $(subcell_size)px;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

toolbar progressbar trough,
palette progressbar trough {
    background: @black;
}

/* Separators */

separator {
    /*border-top: $(thickness)px solid @button_grey;*/
    background-color: @button_grey;
}

/* Tool buttons */

toolbar,
toolbarbox {
    padding: 0;
    background: @toolbar_grey;
    color: @white;
}

/* FIXME: I needed to add the margin in the gtk3.20 port, but that wasn't
          there in the code before.  I ended up having to reduce the border
          to 2px */
toolbutton button,
filtertoolbutton button {
    border-style: none;
    background: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding - default_padding)px;
    margin: $(default_padding)px;
}

toolbutton button #gtk-toolbar-arrow {
    padding: 0 $(subcell_size + default_padding)px;
}

toolbutton button:disabled {
    opacity: $(disabled_opacity);
}

toolbutton button:hover {
    padding: $(toolbutton_padding - 2 - default_padding)px;
    border-width: 2px;
    border-style: solid;
    background-clip: padding-box;
}

toolbutton button:hover:not(:checked),
toolbutton button:hover:not(:checked) * {
    background: @black;
}

toolbutton button.radio:checked,
toolbutton button.radio:checked * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

toolbutton button.radio:checked:hover,
toolbutton button.radio:checked:hover * {
    background: @button_grey;
    border-color: @button_grey;
}

toolbutton button:active,
toolbutton button:active * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

palette scrolledwindow {
    background: @black;
}

toolbar combobox button {
    border-radius: $(2*subcell_size)px;
}

/* Scales */

scale {
    -GtkScale-slider-length: $scale_slider_width;
    -GtkRange-slider-width: $scale_slider_width;
}

scale highlight {
    background: @white;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

scale trough {
    background: @button_grey;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
    margin: $(scale_trough_margin)px 0;
}

scale.vertical trough {
    margin: 0 $(scale_trough_margin)px;
}

scale trough:focus {
    border-color: @white;
}

scale trough,
scale highlight {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px;
}

scale slider,
scale slider:active {
    background: transparent;
}

scale slider {
    background-image: url("assets/scale-slider.svg");
}

scale slider:active {
    background-image: url("assets/scale-slider-active.svg");
}

/* Radio and check buttons */

check:hover {
    background: alpha(@theme_base_color, 0.0);
}

toolbar check,
palette check {
    color: @theme_base_color;
    border: 1px solid @theme_base_color;
}

radio,
radio row:selected,
radio row:selected:focus {
    -gtk-icon-source: url("assets/radio.svg");
    background: alpha(@theme_base_color, 0.0);
}

radio:selected,
radio:selected row:selected,
radio:selected row:selected:focus {
    -gtk-icon-source: url("assets/radio-selected.svg");
}

radio:active,
radio row:selected:active,
radio row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active.svg");
}

radio:checked,
radio row:selected:checked,
radio row:selected:focus:checked {
   -gtk-icon-source: url("assets/radio-active.svg");
}

radio:active:selected,
radio:selected row:selected:active,
radio:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

radio:checked:selected,
radio:selected row:selected:checked,
radio:selected row:selected:focus:checked {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

check,
check row:selected,
check row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked.svg");
    background: alpha(@theme_base_color, 0.0);
}

check:selected,
check:selected row:selected,
check:selected row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked-selected.svg");
}

check:active,
check row:selected:active,
check row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:checked,
check row:selected:checked,
check row:selected:focus:checked {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:active:selected,
check:selected row:selected:active,
check:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

check:checked:selected,
check:selected row:selected:checked,
check:selected row:selected:focus:checked {
    background-image: url("assets/checkbox-checked-selected.svg");
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

/* Tool items */

toolitem {
    /* arrow in the toolbarbox */
    color: @white;
}

.palette-down,
.toolbar-down {
    /* outline of the toolbarbutton when palette is expanded */
    border-style: solid;
    border-width: 2px;
    border-color: @button_grey;
}

/* GtkImage */

image {
    background: transparent;
}

/* Sugar Frame Window */

framewindow {
    background: @toolbar_grey;
}

/* Sugar Canvas icon */

canvasicon {
    border-color: transparent;
    border-radius: $(4 * thickness)px;
    border-width: 2px;
    border-style: solid;
    background: transparent;
}

canvasicon:hover {
    border-color: @zoom_views_prelight;
    background: @zoom_views_prelight;
}

canvasicon.toggle-press {
    border-color: @zoom_views_active;
    background: @zoom_views_active;
}

/* Sugar CellRenderer Icons */

.cell.sugar-icon-cell {
    background: transparent;
    border-radius: $(4 * thickness)px;
    border-color: @white;
    border-width: $(thickness)px;
    border-style: solid;
}

.cell.sugar-icon-cell:hover {
    background: @zoom_views_prelight;
}

.cell.sugar-icon-cell:active {
    background: @zoom_views_active;
}

/* CellRendererProgress */

.cell.progressbar, .cell.trough {
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @selection_grey;
    border-radius: $(2*subcell_size)px;
}

.cell.progressbar {
    background: @white;
}

.cell.trough {
    background: @text_field_grey;
}

/* Text cursor handles */

cursor-handle.top,
cursor-handle.bottom {
    background: transparent;
    border-radius: 10px;
    border-width: $(thickness)px;
    border-color: @panel_grey;
    border-style: solid;
}

cursor-handle.bottom {
    -gtk-icon-source: url("assets/cursor-handle-bottom.svg");
}

cursor-handle.top {
    -gtk-icon-source: url("assets/cursor-handle-top.svg");
}

cursor-handle.insertion-cursor {
    -gtk-icon-source: url("assets/cursor-handle-insertion.svg");
}

/* Application specific properties */

EvView {
    background: @panel_grey;
}

EvView:selected,
ApDocView:selected {
    background: @selection_grey;
}


'simplify' const key management (#227)

'simplify' const key management (#227)

// generated from rosidl_generator_c/resource/msg__struct.h.em
// generated code does not contain a copyright notice

@#######################################################################
@# EmPy template for generating <msg>__struct.h files
@#
@# Context:
@#  - spec (rosidl_parser.MessageSpecification)
@#    Parsed specification of the .msg file
@#  - subfolder (string)
@#    The subfolder / subnamespace of the message
@#    Either 'msg' or 'srv'
@#  - get_header_filename_from_msg_name (function)
@#######################################################################
@
@{
from rosidl_generator_c import msg_type_to_c
from rosidl_generator_c import MSG_TYPE_TO_C
from rosidl_generator_c import primitive_value_to_c

header_guard_parts = [
    spec.base_type.pkg_name, subfolder,
    get_header_filename_from_msg_name(spec.base_type.type) + '__struct_h']
header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_'

msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
array_typename = '%s__Array' % msg_typename
}@
#ifndef @(header_guard_variable)
#define @(header_guard_variable)

#if __cplusplus
extern "C"
{
#endif

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

@#######################################################################
@# include message dependencies
@#######################################################################
@{
from collections import OrderedDict
includes = OrderedDict()
for field in spec.fields:
    if field.type.is_primitive_type():
        if field.type.type == 'string':
            field_names = includes.setdefault('rosidl_generator_c/string.h', [])
            field_names.append(field.name)
        else:
            if field.type.is_dynamic_array():
                field_names = includes.setdefault('rosidl_generator_c/primitives_array.h', [])
                field_names.append(field.name)
    else:
        field_names = includes.setdefault(
            '%s/msg/%s__struct.h' %
                (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)),
            [])
        field_names.append(field.name)
}@
@
@#######################################################################
@# constants defined in the message
@#######################################################################
@{
constants = []
for constant in spec.constants:
    if constant.type in ['byte', 'char', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64']:
        constants.append((
            'enum',
            constant.name,
            '%s__%s' % (msg_typename, constant.name),
            primitive_value_to_c(constant.type, constant.value),
        ))
    else:
        constants.append((
            'static',
            constant.name,
            '%s %s' % (constant.type, msg_typename + '__' + constant.name),
            primitive_value_to_c(constant.type, constant.value),
        ))
}@
@[if includes]@
// include message dependencies
@[  for header_file, field_names in includes.items()]@
@[    for field_name in field_names]@
// @(field_name)
@[    end for]@
#include "@(header_file)"
@[  end for]@

@[end if]@
@[if constants]@
// constants defined in the message
@[  for constant_type, constant_name, key, value in constants]@
// @(constant_name)
@[    if constant_type == 'enum']@
enum
{
  @(key) = @(value)
};
@[    else]@
@{
(const_idl_type, const_c_name) = key.split()
if const_idl_type == 'string':
    const_c_type = 'char * const '
else:
    const_c_type = MSG_TYPE_TO_C[const_idl_type]
}@
static const @(const_c_type) @(const_c_name) = @(value);
@[    end if]@
@[  end for]@

@[end if]@
@
@#######################################################################
@# Constants for array fields with an upper bound
@#######################################################################
@{
upper_bounds = []
for field in spec.fields:
    if field.type.type == 'string' and field.type.string_upper_bound is not None:
        upper_bounds.append((
            field.name,
            '%s__%s__MAX_STRING_SIZE' % (msg_typename, field.name),
            field.type.string_upper_bound,
        ))
    if field.type.is_array and field.type.array_size and field.type.is_upper_bound:
        upper_bounds.append((
            field.name,
            '%s__%s__MAX_SIZE' % (msg_typename, field.name),
            field.type.array_size,
        ))
}@
@[if upper_bounds]@
// constants for array fields with an upper bound
@[  for field_name, enum_name, enum_value in upper_bounds]@
// @(field_name)
enum
{
  @(enum_name) = @(enum_value)
};
@[  end for]@

@[end if]@
@
@#######################################################################
@# Struct of message
@#######################################################################
/// Struct of message @(spec.base_type.pkg_name)/@(spec.base_type.type)
typedef struct @(msg_typename)
{
@[for field in spec.fields]@
  @(msg_type_to_c(field.type, field.name));
@[end for]@
@[if not spec.fields]@
  bool _dummy;
@[end if]@
} @(msg_typename);

@#######################################################################
@# Struct for an array of messages
@#######################################################################
/// Struct for an array of messages
typedef struct @(array_typename)
{
  @(msg_typename) * data;
  /// The number of valid items in data
  size_t size;
  /// The number of allocated items in data
  size_t capacity;
} @(array_typename);

#if __cplusplus
}
#endif

#endif  // @(header_guard_variable)

// generated from rosidl_generator_c/resource/msg__struct.h.em
// generated code does not contain a copyright notice

@#######################################################################
@# EmPy template for generating <msg>__struct.h files
@#
@# Context:
@#  - spec (rosidl_parser.MessageSpecification)
@#    Parsed specification of the .msg file
@#  - subfolder (string)
@#    The subfolder / subnamespace of the message
@#    Either 'msg' or 'srv'
@#  - get_header_filename_from_msg_name (function)
@#######################################################################
@
@{
from rosidl_generator_c import msg_type_to_c
from rosidl_generator_c import MSG_TYPE_TO_C
from rosidl_generator_c import primitive_value_to_c

header_guard_parts = [
    spec.base_type.pkg_name, subfolder,
    get_header_filename_from_msg_name(spec.base_type.type) + '__struct_h']
header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_'

msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
array_typename = '%s__Array' % msg_typename
}@
#ifndef @(header_guard_variable)
#define @(header_guard_variable)

#if __cplusplus
extern "C"
{
#endif

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

@#######################################################################
@# include message dependencies
@#######################################################################
@{
from collections import OrderedDict
includes = OrderedDict()
for field in spec.fields:
    if field.type.is_primitive_type():
        if field.type.type == 'string':
            field_names = includes.setdefault('rosidl_generator_c/string.h', [])
            field_names.append(field.name)
        else:
            if field.type.is_dynamic_array():
                field_names = includes.setdefault('rosidl_generator_c/primitives_array.h', [])
                field_names.append(field.name)
    else:
        field_names = includes.setdefault(
            '%s/msg/%s__struct.h' %
                (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)),
            [])
        field_names.append(field.name)
}@
@
@#######################################################################
@# constants defined in the message
@#######################################################################
@{
constants = []
for constant in spec.constants:
    if constant.type in ['byte', 'char', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64']:
        constants.append((
            'enum',
            constant.name,
            '%s__%s' % (msg_typename, constant.name),
            primitive_value_to_c(constant.type, constant.value),
        ))
    else:
        constants.append((
            'static',
            constant.name,
            '%s %s' % (MSG_TYPE_TO_C[constant.type], msg_typename + '__' + constant.name),
            primitive_value_to_c(constant.type, constant.value),
        ))
}@
@[if includes]@
// include message dependencies
@[  for header_file, field_names in includes.items()]@
@[    for field_name in field_names]@
// @(field_name)
@[    end for]@
#include "@(header_file)"
@[  end for]@

@[end if]@
@[if constants]@
// constants defined in the message
@[  for constant_type, constant_name, key, value in constants]@
// @(constant_name)
@[    if constant_type == 'enum']@
enum
{
  @(key) = @(value)
};
@[    elif key.split()[0] == 'rosidl_generator_c__String']@
@{
name = key.split()[1]
}@
static const char * const @(name) = @(value);
@[    else]@
static const @(key) = @(value);
@[    end if]@
@[  end for]@

@[end if]@
@
@#######################################################################
@# Constants for array fields with an upper bound
@#######################################################################
@{
upper_bounds = []
for field in spec.fields:
    if field.type.type == 'string' and field.type.string_upper_bound is not None:
        upper_bounds.append((
            field.name,
            '%s__%s__MAX_STRING_SIZE' % (msg_typename, field.name),
            field.type.string_upper_bound,
        ))
    if field.type.is_array and field.type.array_size and field.type.is_upper_bound:
        upper_bounds.append((
            field.name,
            '%s__%s__MAX_SIZE' % (msg_typename, field.name),
            field.type.array_size,
        ))
}@
@[if upper_bounds]@
// constants for array fields with an upper bound
@[  for field_name, enum_name, enum_value in upper_bounds]@
// @(field_name)
enum
{
  @(enum_name) = @(enum_value)
};
@[  end for]@

@[end if]@
@
@#######################################################################
@# Struct of message
@#######################################################################
/// Struct of message @(spec.base_type.pkg_name)/@(spec.base_type.type)
typedef struct @(msg_typename)
{
@[for field in spec.fields]@
  @(msg_type_to_c(field.type, field.name));
@[end for]@
@[if not spec.fields]@
  bool _dummy;
@[end if]@
} @(msg_typename);

@#######################################################################
@# Struct for an array of messages
@#######################################################################
/// Struct for an array of messages
typedef struct @(array_typename)
{
  @(msg_typename) * data;
  /// The number of valid items in data
  size_t size;
  /// The number of allocated items in data
  size_t capacity;
} @(array_typename);

#if __cplusplus
}
#endif

#endif  // @(header_guard_variable)