]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/selection.cpp
Merge commit '667d3275589dac91b5bfe96f0244183007be6efd' into master-merge
[xonotic/netradiant.git] / radiant / selection.cpp
index 0086e36312580605da6905106cddb69b2044c48d..2ac9844517fd49c83203c2c6734afcc2d6cd5e33 100644 (file)
@@ -193,8 +193,8 @@ float distance_for_axis( const Vector3& a, const Vector3& b, const Vector3& axis
 class Manipulatable
 {
 public:
-virtual void Construct( const Matrix4& device2manip, const float x, const float y ) = 0;
-virtual void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ) = 0;
+virtual void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ) = 0;
+virtual void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ) = 0;
 };
 
 void transform_local2object( Matrix4& object, const Matrix4& local, const Matrix4& local2object ){
@@ -219,16 +219,30 @@ public:
 RotateFree( Rotatable& rotatable )
        : m_rotatable( rotatable ){
 }
-void Construct( const Matrix4& device2manip, const float x, const float y ){
+void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){
        point_on_sphere( m_start, device2manip, x, y );
        vector3_normalise( m_start );
 }
-void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){
+void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
        Vector3 current;
-
        point_on_sphere( current, device2manip, x, y );
-       vector3_normalise( current );
 
+       if( snap ){
+               Vector3 axis( 0, 0, 0 );
+               for( std::size_t i = 0; i < 3; ++i ){
+                       if( current[i] == 0.0f ){
+                               axis[i] = 1.0f;
+                               break;
+                       }
+               }
+               if( vector3_length_squared( axis ) != 0 ){
+                       constrain_to_axis( current, axis );
+                       m_rotatable.rotate( quaternion_for_axisangle( axis, float_snapped( angle_for_axis( m_start, current, axis ), static_cast<float>( c_pi / 12.0 ) ) ) );
+                       return;
+               }
+       }
+
+       vector3_normalise( current );
        m_rotatable.rotate( quaternion_for_unit_vectors( m_start, current ) );
 }
 };
@@ -242,17 +256,22 @@ public:
 RotateAxis( Rotatable& rotatable )
        : m_rotatable( rotatable ){
 }
-void Construct( const Matrix4& device2manip, const float x, const float y ){
+void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){
        point_on_sphere( m_start, device2manip, x, y );
        constrain_to_axis( m_start, m_axis );
 }
 /// \brief Converts current position to a normalised vector orthogonal to axis.
-void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){
+void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
        Vector3 current;
        point_on_sphere( current, device2manip, x, y );
        constrain_to_axis( current, m_axis );
 
-       m_rotatable.rotate( quaternion_for_axisangle( m_axis, angle_for_axis( m_start, current, m_axis ) ) );
+       if( snap ){
+               m_rotatable.rotate( quaternion_for_axisangle( m_axis, float_snapped( angle_for_axis( m_start, current, m_axis ), static_cast<float>( c_pi / 12.0 ) ) ) );
+       }
+       else{
+               m_rotatable.rotate( quaternion_for_axisangle( m_axis, angle_for_axis( m_start, current, m_axis ) ) );
+       }
 }
 
 void SetAxis( const Vector3& axis ){
@@ -281,20 +300,43 @@ class TranslateAxis : public Manipulatable
 Vector3 m_start;
 Vector3 m_axis;
 Translatable& m_translatable;
+AABB m_bounds;
 public:
 TranslateAxis( Translatable& translatable )
        : m_translatable( translatable ){
 }
-void Construct( const Matrix4& device2manip, const float x, const float y ){
+void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){
        point_on_axis( m_start, m_axis, device2manip, x, y );
+       m_bounds = bounds;
 }
-void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){
+void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
        Vector3 current;
        point_on_axis( current, m_axis, device2manip, x, y );
        current = vector3_scaled( m_axis, distance_for_axis( m_start, current, m_axis ) );
 
        translation_local2object( current, current, manip2object );
-       vector3_snap( current, GetSnapGridSize() );
+       if( snapbbox ){
+               float grid = GetSnapGridSize();
+               Vector3 maxs( m_bounds.origin + m_bounds.extents );
+               Vector3 mins( m_bounds.origin - m_bounds.extents );
+//             globalOutputStream() << "current: " << current << "\n";
+               for( std::size_t i = 0; i < 3; ++i ){
+                       if( m_axis[i] != 0.f ){
+                               float snapto1 = float_snapped( maxs[i] + current[i] , grid );
+                               float snapto2 = float_snapped( mins[i] + current[i] , grid );
+
+                               float dist1 = fabs( fabs( maxs[i] + current[i] ) - fabs( snapto1 ) );
+                               float dist2 = fabs( fabs( mins[i] + current[i] ) - fabs( snapto2 ) );
+
+//                             globalOutputStream() << "maxs[i] + current[i]: " << maxs[i] + current[i]  << "    snapto1: " << snapto1 << "   dist1: " << dist1 << "\n";
+//                             globalOutputStream() << "mins[i] + current[i]: " << mins[i] + current[i]  << "    snapto2: " << snapto2 << "   dist2: " << dist2 << "\n";
+                               current[i] = dist2 > dist1 ? snapto1 - maxs[i] : snapto2 - mins[i];
+                       }
+               }
+       }
+       else{
+               vector3_snap( current, GetSnapGridSize() );
+       }
 
        m_translatable.translate( current );
 }
@@ -309,28 +351,57 @@ class TranslateFree : public Manipulatable
 private:
 Vector3 m_start;
 Translatable& m_translatable;
+AABB m_bounds;
 public:
 TranslateFree( Translatable& translatable )
        : m_translatable( translatable ){
 }
-void Construct( const Matrix4& device2manip, const float x, const float y ){
+void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){
        point_on_plane( m_start, device2manip, x, y );
+       m_bounds = bounds;
 }
-void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){
+void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
        Vector3 current;
        point_on_plane( current, device2manip, x, y );
        current = vector3_subtracted( current, m_start );
 
+       if( snap ){
+               for ( std::size_t i = 0; i < 3 ; ++i ){
+                       if( fabs( current[i] ) >= fabs( current[(i + 1) % 3] ) ){
+                               current[(i + 1) % 3] = 0.0f;
+                       }
+                       else{
+                               current[i] = 0.0f;
+                       }
+               }
+       }
+
        translation_local2object( current, current, manip2object );
-       vector3_snap( current, GetSnapGridSize() );
+       if( snapbbox ){
+               float grid = GetSnapGridSize();
+               Vector3 maxs( m_bounds.origin + m_bounds.extents );
+               Vector3 mins( m_bounds.origin - m_bounds.extents );
+               //globalOutputStream() << "current: " << current << "\n";
+               for( std::size_t i = 0; i < 3; ++i ){
+                       if( fabs( current[i] ) > 0.000001f ){
+                               float snapto1 = float_snapped( maxs[i] + current[i] , grid );
+                               float snapto2 = float_snapped( mins[i] + current[i] , grid );
+
+                               float dist1 = fabs( fabs( maxs[i] + current[i] ) - fabs( snapto1 ) );
+                               float dist2 = fabs( fabs( mins[i] + current[i] ) - fabs( snapto2 ) );
+
+                               current[i] = dist2 > dist1 ? snapto1 - maxs[i] : snapto2 - mins[i];
+                       }
+               }
+       }
+       else{
+               vector3_snap( current, GetSnapGridSize() );
+       }
 
        m_translatable.translate( current );
 }
 };
 
-void GetSelectionAABB( AABB& bounds );
-const Matrix4& ssGetPivot2World();
-
 class Scalable
 {
 public:
@@ -346,26 +417,24 @@ Vector3 m_start;
 Vector3 m_axis;
 Scalable& m_scalable;
 
-AABB m_aabb;
-Vector3 m_transform_origin;
 Vector3 m_choosen_extent;
+AABB m_bounds;
 
 public:
 ScaleAxis( Scalable& scalable )
        : m_scalable( scalable ){
 }
-void Construct( const Matrix4& device2manip, const float x, const float y ){
+void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){
        point_on_axis( m_start, m_axis, device2manip, x, y );
 
-       GetSelectionAABB( m_aabb );
-       m_transform_origin = vector4_to_vector3( ssGetPivot2World().t() );
-       m_choosen_extent = Vector3( std::max( m_aabb.origin[0] + m_aabb.extents[0] - m_transform_origin[0], - m_aabb.origin[0] + m_aabb.extents[0] + m_transform_origin[0] ),
-                                       std::max( m_aabb.origin[1] + m_aabb.extents[1] - m_transform_origin[1], - m_aabb.origin[1] + m_aabb.extents[1] + m_transform_origin[1] ),
-                                       std::max( m_aabb.origin[2] + m_aabb.extents[2] - m_transform_origin[2], - m_aabb.origin[2] + m_aabb.extents[2] + m_transform_origin[2] )
+       m_choosen_extent = Vector3(
+                                       std::max( bounds.origin[0] + bounds.extents[0] - transform_origin[0], - bounds.origin[0] + bounds.extents[0] + transform_origin[0] ),
+                                       std::max( bounds.origin[1] + bounds.extents[1] - transform_origin[1], - bounds.origin[1] + bounds.extents[1] + transform_origin[1] ),
+                                       std::max( bounds.origin[2] + bounds.extents[2] - transform_origin[2], - bounds.origin[2] + bounds.extents[2] + transform_origin[2] )
                                                        );
-
+       m_bounds = bounds;
 }
-void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){
+void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
        //globalOutputStream() << "manip2object: " << manip2object << "  device2manip: " << device2manip << "  x: " << x << "  y:" << y <<"\n";
        Vector3 current;
        point_on_axis( current, m_axis, device2manip, x, y );
@@ -374,8 +443,13 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
        translation_local2object( delta, delta, manip2object );
        vector3_snap( delta, GetSnapGridSize() );
 
-       Vector3 start( vector3_snapped( m_start, GetSnapGridSize() ) );
-       //globalOutputStream() << "start: " << start << "   delta: " << delta <<"\n";
+       Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.0f ? GetSnapGridSize() : 0.001f ) );
+       for ( std::size_t i = 0; i < 3 ; ++i ){ //prevent snapping to 0 with big gridsize
+               if( float_snapped( m_start[i], 0.001f ) != 0.0f && start[i] == 0.0f ){
+                       start[i] = GetSnapGridSize();
+               }
+       }
+       //globalOutputStream() << "m_start: " << m_start << "   start: " << start << "   delta: " << delta <<"\n";
        Vector3 scale(
                start[0] == 0 ? 1 : 1 + delta[0] / start[0],
                start[1] == 0 ? 1 : 1 + delta[1] / start[1],
@@ -383,11 +457,22 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
                );
 
        for( std::size_t i = 0; i < 3; i++ ){
-               if( m_choosen_extent[i] > 0.0625 ){ //epsilon to prevent too high scale for set of models, having really small extent, formed by origins
+               if( m_choosen_extent[i] > 0.0625f && m_axis[i] != 0.f ){ //epsilon to prevent super high scale for set of models, having really small extent, formed by origins
                        scale[i] = ( m_choosen_extent[i] + delta[i] ) / m_choosen_extent[i];
+                       if( snapbbox ){
+                               float snappdwidth = float_snapped( scale[i] * m_bounds.extents[i] * 2.f, GetSnapGridSize() );
+                               scale[i] = snappdwidth / ( m_bounds.extents[i] * 2.f );
+                       }
                }
        }
-
+       if( snap ){
+               for( std::size_t i = 0; i < 3; i++ ){
+                       if( scale[i] == 1.0f ){
+                               scale[i] = vector3_dot( scale, m_axis );
+                       }
+               }
+       }
+       //globalOutputStream() << "scale: " << scale <<"\n";
        m_scalable.scale( scale );
 }
 
@@ -402,25 +487,24 @@ private:
 Vector3 m_start;
 Scalable& m_scalable;
 
-AABB m_aabb;
-Vector3 m_transform_origin;
 Vector3 m_choosen_extent;
+AABB m_bounds;
 
 public:
 ScaleFree( Scalable& scalable )
        : m_scalable( scalable ){
 }
-void Construct( const Matrix4& device2manip, const float x, const float y ){
+void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){
        point_on_plane( m_start, device2manip, x, y );
 
-       GetSelectionAABB( m_aabb );
-       m_transform_origin = vector4_to_vector3( ssGetPivot2World().t() );
-       m_choosen_extent = Vector3( std::max( m_aabb.origin[0] + m_aabb.extents[0] - m_transform_origin[0], - m_aabb.origin[0] + m_aabb.extents[0] + m_transform_origin[0] ),
-                                       std::max( m_aabb.origin[1] + m_aabb.extents[1] - m_transform_origin[1], - m_aabb.origin[1] + m_aabb.extents[1] + m_transform_origin[1] ),
-                                       std::max( m_aabb.origin[2] + m_aabb.extents[2] - m_transform_origin[2], - m_aabb.origin[2] + m_aabb.extents[2] + m_transform_origin[2] )
+       m_choosen_extent = Vector3(
+                                       std::max( bounds.origin[0] + bounds.extents[0] - transform_origin[0], - bounds.origin[0] + bounds.extents[0] + transform_origin[0] ),
+                                       std::max( bounds.origin[1] + bounds.extents[1] - transform_origin[1], - bounds.origin[1] + bounds.extents[1] + transform_origin[1] ),
+                                       std::max( bounds.origin[2] + bounds.extents[2] - transform_origin[2], - bounds.origin[2] + bounds.extents[2] + transform_origin[2] )
                                                        );
+       m_bounds = bounds;
 }
-void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){
+void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
        Vector3 current;
        point_on_plane( current, device2manip, x, y );
        Vector3 delta = vector3_subtracted( current, m_start );
@@ -428,19 +512,45 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
        translation_local2object( delta, delta, manip2object );
        vector3_snap( delta, GetSnapGridSize() );
 
-       Vector3 start( vector3_snapped( m_start, GetSnapGridSize() ) );
+       Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.0f ? GetSnapGridSize() : 0.001f ) );
+       for ( std::size_t i = 0; i < 3 ; ++i ){ //prevent snapping to 0 with big gridsize
+               if( float_snapped( m_start[i], 0.001f ) != 0.0f && start[i] == 0.0f ){
+                       start[i] = GetSnapGridSize();
+               }
+       }
        Vector3 scale(
                start[0] == 0 ? 1 : 1 + delta[0] / start[0],
                start[1] == 0 ? 1 : 1 + delta[1] / start[1],
                start[2] == 0 ? 1 : 1 + delta[2] / start[2]
                );
 
+       //globalOutputStream() << "m_start: " << m_start << "   start: " << start << "   delta: " << delta <<"\n";
        for( std::size_t i = 0; i < 3; i++ ){
-               if( m_choosen_extent[i] > 0.0625 ){
+               if( m_choosen_extent[i] > 0.0625f ){
                        scale[i] = ( m_choosen_extent[i] + delta[i] ) / m_choosen_extent[i];
+                       if( snapbbox && start[i] != 0.f ){
+                               float snappdwidth = float_snapped( scale[i] * m_bounds.extents[i] * 2.f, GetSnapGridSize() );
+                               scale[i] = snappdwidth / ( m_bounds.extents[i] * 2.f );
+                       }
                }
        }
-
+       //globalOutputStream() << "pre snap scale: " << scale <<"\n";
+       if( snap ){
+               float bestscale = scale[0];
+               for( std::size_t i = 1; i < 3; i++ ){
+                       //if( fabs( 1.0f - fabs( scale[i] ) ) > fabs( 1.0f - fabs( bestscale ) ) ){
+                       if( fabs( scale[i] ) > fabs( bestscale ) && scale[i] != 1.0f ){ //harder to scale down with this, but glitchier with upper one
+                               bestscale = scale[i];
+                       }
+                       //globalOutputStream() << "bestscale: " << bestscale <<"\n";
+               }
+               for( std::size_t i = 0; i < 3; i++ ){
+                       if( start[i] != 0.0f ){ // !!!!check grid == 0 case
+                               scale[i] = ( scale[i] < 0.0f ) ? -fabs( bestscale ) : fabs( bestscale );
+                       }
+               }
+       }
+       //globalOutputStream() << "scale: " << scale <<"\n";
        m_scalable.scale( scale );
 }
 };
@@ -946,6 +1056,8 @@ RotateManipulator( Rotatable& rotatable, std::size_t segments, float radius ) :
 
        draw_circle( segments, radius * 1.15f, m_circle_screen.m_vertices.data(), RemapXYZ() );
        draw_circle( segments, radius, m_circle_sphere.m_vertices.data(), RemapXYZ() );
+
+       m_selectable_sphere.setSelected( true );
 }
 
 
@@ -1779,6 +1891,59 @@ bool Scene_forEachPlaneSelectable_selectPlanes( scene::Graph& graph, Selector& s
        return !selectedPlanes.empty();
 }
 
+
+#include "brush.h"
+/*
+class TestedBrushPlanesSelectVeritces : public scene::Graph::Walker
+{
+SelectionTest& m_test;
+public:
+TestedBrushPlanesSelectVeritces( SelectionTest& test )
+       : m_test( test ){
+}
+bool pre( const scene::Path& path, scene::Instance& instance ) const {
+       if ( path.top().get().visible() ) {
+               Selectable* selectable = Instance_getSelectable( instance );
+               if ( selectable != 0 && selectable->isSelected() ) {
+                       BrushInstance* brushInstance = Instance_getBrush( instance );
+                       if ( brushInstance != 0 ) {
+                               brushInstance->selectVerticesOnPlanes( m_test );
+                       }
+               }
+       }
+       return true;
+}
+};
+
+void Scene_forEachTestedBrushPlane_selectVertices( scene::Graph& graph, SelectionTest& test ){
+       graph.traverse( TestedBrushPlanesSelectVeritces( test ) );
+}
+*/
+class BrushPlanesSelectVeritces : public scene::Graph::Walker
+{
+SelectionTest& m_test;
+public:
+BrushPlanesSelectVeritces( SelectionTest& test )
+       : m_test( test ){
+}
+bool pre( const scene::Path& path, scene::Instance& instance ) const {
+       if ( path.top().get().visible() ) {
+               Selectable* selectable = Instance_getSelectable( instance );
+               if ( selectable != 0 && selectable->isSelected() ) {
+                       BrushInstance* brushInstance = Instance_getBrush( instance );
+                       if ( brushInstance != 0 ) {
+                               brushInstance->selectVerticesOnPlanes( m_test );
+                       }
+               }
+       }
+       return true;
+}
+};
+
+void Scene_forEachBrushPlane_selectVertices( scene::Graph& graph, SelectionTest& test ){
+       graph.traverse( BrushPlanesSelectVeritces( test ) );
+}
+
 void Scene_Translate_Component_Selected( scene::Graph& graph, const Vector3& translation );
 void Scene_Translate_Selected( scene::Graph& graph, const Vector3& translation );
 void Scene_TestSelect_Primitive( Selector& selector, SelectionTest& test, const VolumeTest& volume );
@@ -2442,16 +2607,54 @@ std::list<Selectable*>& best(){
 }
 };
 
+class DeepBestSelector : public Selector
+{
+SelectionIntersection m_intersection;
+Selectable* m_selectable;
+SelectionIntersection m_bestIntersection;
+std::list<Selectable*> m_bestSelectable;
+public:
+DeepBestSelector() : m_bestIntersection( SelectionIntersection() ), m_bestSelectable( 0 ){
+}
+
+void pushSelectable( Selectable& selectable ){
+       m_intersection = SelectionIntersection();
+       m_selectable = &selectable;
+}
+void popSelectable(){
+       if ( m_intersection.equalEpsilon( m_bestIntersection, 0.25f, 2.f ) ) {
+               m_bestSelectable.push_back( m_selectable );
+               m_bestIntersection = m_intersection;
+       }
+       else if ( m_intersection < m_bestIntersection ) {
+               m_bestSelectable.clear();
+               m_bestSelectable.push_back( m_selectable );
+               m_bestIntersection = m_intersection;
+       }
+       m_intersection = SelectionIntersection();
+}
+void addIntersection( const SelectionIntersection& intersection ){
+       assign_if_closer( m_intersection, intersection );
+}
+
+std::list<Selectable*>& best(){
+       return m_bestSelectable;
+}
+};
+
+bool g_bAltDragManipulatorResize = false; //+select primitives in component modes
+bool g_bTmpComponentMode = false;
+
 class DragManipulator : public Manipulator
 {
 TranslateFree m_freeResize;
 TranslateFree m_freeDrag;
 ResizeTranslatable m_resize;
 DragTranslatable m_drag;
-SelectableBool m_dragSelectable;
+SelectableBool m_dragSelectable; //drag already selected stuff
 public:
 
-bool m_selected;
+bool m_selected; //selected temporally for drag
 
 DragManipulator() : m_freeResize( m_resize ), m_freeDrag( m_drag ), m_selected( false ){
 }
@@ -2471,12 +2674,38 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
                Scene_TestSelect_Primitive( booleanSelector, test, view );
 
                if ( booleanSelector.isSelected() ) {
-                       selector.addSelectable( SelectionIntersection( 0, 0 ), &m_dragSelectable );
-                       m_selected = false;
+                       if( g_bAltDragManipulatorResize ){
+                               DeepBestSelector deepSelector;
+                               Scene_TestSelect_Component_Selected( deepSelector, test, view, SelectionSystem::eVertex );
+                               for ( std::list<Selectable*>::iterator i = deepSelector.best().begin(); i != deepSelector.best().end(); ++i )
+                               {
+                                       if ( !( *i )->isSelected() ) {
+                                               GlobalSelectionSystem().setSelectedAllComponents( false );
+                                       }
+                                       selector.addSelectable( SelectionIntersection( 0, 0 ), ( *i ) );
+                                       m_selected = true;
+                                       m_dragSelectable.setSelected( false );
+                               }
+                               if( deepSelector.best().empty() ){
+                                       //Scene_forEachTestedBrushPlane_selectVertices( GlobalSceneGraph(), test );     //todo? drag clicked face
+                                       Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test );
+                                       m_selected = true;
+                               }
+                       }
+                       else{
+                               selector.addSelectable( SelectionIntersection( 0, 0 ), &m_dragSelectable );
+                               m_selected = false;
+                       }
                }
                else
                {
-                       m_selected = Scene_forEachPlaneSelectable_selectPlanes( GlobalSceneGraph(), selector, test );
+                       if( g_bAltDragManipulatorResize ){
+                               Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test );
+                               m_selected = true;
+                       }
+                       else{
+                               m_selected = Scene_forEachPlaneSelectable_selectPlanes( GlobalSceneGraph(), selector, test );
+                       }
                }
        }
        else
@@ -2492,12 +2721,16 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
                        selector.addSelectable( SelectionIntersection( 0, 0 ), ( *i ) );
                        m_dragSelectable.setSelected( true );
                }
+               if( GlobalSelectionSystem().countSelectedComponents() != 0 ){
+                       m_dragSelectable.setSelected( true );
+               }
        }
 
        for ( SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i )
        {
                ( *i ).second->setSelected( true );
        }
+       g_bTmpComponentMode = m_selected;
 }
 
 void setSelected( bool select ){
@@ -2579,6 +2812,7 @@ Rotation m_rotation;
 Scale m_scale;
 public:
 static Shader* m_state;
+bool m_bPreferPointEntsIn2D;
 private:
 EManipulatorMode m_manipulator_mode;
 Manipulator* m_manipulator;
@@ -2606,7 +2840,7 @@ Signal1<const Selectable&> m_selectionChanged_callbacks;
 void ConstructPivot() const;
 void setCustomPivotOrigin( Vector3& point ) const;
 public:
-void getSelectionAABB( AABB& bounds ) const;
+AABB getSelectionAABB() const;
 private:
 mutable bool m_pivotChanged;
 bool m_pivot_moving;
@@ -2632,6 +2866,7 @@ enum EModifier
 };
 
 RadiantSelectionSystem() :
+       m_bPreferPointEntsIn2D( true ),
        m_undo_begun( false ),
        m_mode( ePrimitive ),
        m_componentmode( eDefault ),
@@ -2802,7 +3037,7 @@ bool SelectManipulator( const View& view, const float device_point[2], const flo
 
                        Matrix4 device2manip;
                        ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() );
-                       m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1] );
+                       m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) );
 
                        m_undo_begun = false;
                }
@@ -2856,73 +3091,32 @@ void SelectPoint( const View& view, const float device_point[2], const float dev
 
                SelectionVolume volume( scissored );
                SelectionPool selector;
-               if ( face ) {
-                       Scene_TestSelect_Component( selector, volume, scissored, eFace );
-               }
-               else
-               {
-                       Scene_TestSelect( selector, volume, scissored, Mode(), ComponentMode() );
-               }
+               SelectionPool selector_point_ents;
+               const bool prefer_point_ents = m_bPreferPointEntsIn2D && Mode() == ePrimitive && !view.fill() && !face
+                       && ( modifier == RadiantSelectionSystem::eReplace || modifier == RadiantSelectionSystem::eSelect || modifier == RadiantSelectionSystem::eDeselect );
 
-               if ( !selector.failed() ) {
+               if( prefer_point_ents ){
+                       Scene_TestSelect( selector_point_ents, volume, scissored, eEntity, ComponentMode() );
+               }
+               if( prefer_point_ents && !selector_point_ents.failed() ){
                        switch ( modifier )
                        {
-                       case RadiantSelectionSystem::eToggle:
-                       {
-                               SelectableSortedSet::iterator best = selector.begin();
-                               // toggle selection of the object with least depth
-                               if ( ( *best ).second->isSelected() ) {
-                                       ( *best ).second->setSelected( false );
-                               }
-                               else{
-                                       ( *best ).second->setSelected( true );
-                               }
-                       }
-                       break;
                        // if cycle mode not enabled, enable it
                        case RadiantSelectionSystem::eReplace:
                        {
                                // select closest
-                               ( *selector.begin() ).second->setSelected( true );
-                       }
-                       break;
-                       // select the next object in the list from the one already selected
-                       case RadiantSelectionSystem::eCycle:
-                       {
-                               bool CycleSelectionOccured = false;
-                               SelectionPool::iterator i = selector.begin();
-                               while ( i != selector.end() )
-                               {
-                                       if ( ( *i ).second->isSelected() ) {
-                                               deselectComponentsOrAll( face );
-                                               ++i;
-                                               if ( i != selector.end() ) {
-                                                       i->second->setSelected( true );
-                                               }
-                                               else
-                                               {
-                                                       selector.begin()->second->setSelected( true );
-                                               }
-                                               CycleSelectionOccured = true;
-                                               break;
-                                       }
-                                       ++i;
-                               }
-                               if( !CycleSelectionOccured ){
-                                       deselectComponentsOrAll( face );
-                                       ( *selector.begin() ).second->setSelected( true );
-                               }
+                               ( *selector_point_ents.begin() ).second->setSelected( true );
                        }
                        break;
                        case RadiantSelectionSystem::eSelect:
                        {
-                               SelectionPool::iterator best = selector.begin();
+                               SelectionPool::iterator best = selector_point_ents.begin();
                                if( !( *best ).second->isSelected() ){
                                        ( *best ).second->setSelected( true );
                                }
                                SelectionPool::iterator i = best;
                                ++i;
-                               while ( i != selector.end() )
+                               while ( i != selector_point_ents.end() )
                                {
                                        if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
                                                if( !( *i ).second->isSelected() ){
@@ -2938,13 +3132,13 @@ void SelectPoint( const View& view, const float device_point[2], const float dev
                        break;
                        case RadiantSelectionSystem::eDeselect:
                        {
-                               SelectionPool::iterator best = selector.begin();
+                               SelectionPool::iterator best = selector_point_ents.begin();
                                if( ( *best ).second->isSelected() ){
                                        ( *best ).second->setSelected( false );
                                }
                                SelectionPool::iterator i = best;
                                ++i;
-                               while ( i != selector.end() )
+                               while ( i != selector_point_ents.end() )
                                {
                                        if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
                                                if( ( *i ).second->isSelected() ){
@@ -2962,8 +3156,115 @@ void SelectPoint( const View& view, const float device_point[2], const float dev
                                break;
                        }
                }
-               else if( modifier == eCycle ){
-                       deselectComponentsOrAll( face );
+               else{
+                       if ( face ){
+                               Scene_TestSelect_Component( selector, volume, scissored, eFace );
+                       }
+                       else{
+                               Scene_TestSelect( selector, volume, scissored, g_bAltDragManipulatorResize ? ePrimitive : Mode(), ComponentMode() );
+                       }
+
+                       if ( !selector.failed() ) {
+                               switch ( modifier )
+                               {
+                               case RadiantSelectionSystem::eToggle:
+                               {
+                                       SelectableSortedSet::iterator best = selector.begin();
+                                       // toggle selection of the object with least depth
+                                       if ( ( *best ).second->isSelected() ) {
+                                               ( *best ).second->setSelected( false );
+                                       }
+                                       else{
+                                               ( *best ).second->setSelected( true );
+                                       }
+                               }
+                               break;
+                               // if cycle mode not enabled, enable it
+                               case RadiantSelectionSystem::eReplace:
+                               {
+                                       // select closest
+                                       ( *selector.begin() ).second->setSelected( true );
+                               }
+                               break;
+                               // select the next object in the list from the one already selected
+                               case RadiantSelectionSystem::eCycle:
+                               {
+                                       bool CycleSelectionOccured = false;
+                                       SelectionPool::iterator i = selector.begin();
+                                       while ( i != selector.end() )
+                                       {
+                                               if ( ( *i ).second->isSelected() ) {
+                                                       deselectComponentsOrAll( face );
+                                                       ++i;
+                                                       if ( i != selector.end() ) {
+                                                               i->second->setSelected( true );
+                                                       }
+                                                       else
+                                                       {
+                                                               selector.begin()->second->setSelected( true );
+                                                       }
+                                                       CycleSelectionOccured = true;
+                                                       break;
+                                               }
+                                               ++i;
+                                       }
+                                       if( !CycleSelectionOccured ){
+                                               deselectComponentsOrAll( face );
+                                               ( *selector.begin() ).second->setSelected( true );
+                                       }
+                               }
+                               break;
+                               case RadiantSelectionSystem::eSelect:
+                               {
+                                       SelectionPool::iterator best = selector.begin();
+                                       if( !( *best ).second->isSelected() ){
+                                               ( *best ).second->setSelected( true );
+                                       }
+                                       SelectionPool::iterator i = best;
+                                       ++i;
+                                       while ( i != selector.end() )
+                                       {
+                                               if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
+                                                       if( !( *i ).second->isSelected() ){
+                                                               ( *i ).second->setSelected( true );
+                                                       }
+                                               }
+                                               else{
+                                                       break;
+                                               }
+                                               ++i;
+                                       }
+                               }
+                               break;
+                               case RadiantSelectionSystem::eDeselect:
+                               {
+                                       SelectionPool::iterator best = selector.begin();
+                                       if( ( *best ).second->isSelected() ){
+                                               ( *best ).second->setSelected( false );
+                                       }
+                                       SelectionPool::iterator i = best;
+                                       ++i;
+                                       while ( i != selector.end() )
+                                       {
+                                               if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
+                                                       if( ( *i ).second->isSelected() ){
+                                                               ( *i ).second->setSelected( false );
+                                                       }
+                                               }
+                                               else{
+                                                       break;
+                                               }
+                                               ++i;
+                                       }
+                               }
+                               break;
+                               default:
+                                       break;
+                               }
+                       }
+                       else if( modifier == eCycle ){
+                               deselectComponentsOrAll( face );
+                       }
                }
        }
 }
@@ -2980,21 +3281,19 @@ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const
 
                SelectionVolume volume( scissored );
                SelectionPool selector;
-               if ( face ) {
-                       Scene_TestSelect_Component( selector, volume, scissored, eFace );
-               }
-               else
-               {
-                       Scene_TestSelect( selector, volume, scissored, Mode(), ComponentMode() );
-               }
+               SelectionPool selector_point_ents;
+               const bool prefer_point_ents = m_bPreferPointEntsIn2D && Mode() == ePrimitive && !view.fill() && !face;
 
-               if ( !selector.failed() ) {
-                       SelectableSortedSet::iterator best = selector.begin();
+               if( prefer_point_ents ){
+                       Scene_TestSelect( selector_point_ents, volume, scissored, eEntity, ComponentMode() );
+               }
+               if( prefer_point_ents && !selector_point_ents.failed() ){
+                       SelectableSortedSet::iterator best = selector_point_ents.begin();
                        const bool wasSelected = ( *best ).second->isSelected();
                        ( *best ).second->setSelected( !wasSelected );
                        SelectableSortedSet::iterator i = best;
                        ++i;
-                       while ( i != selector.end() )
+                       while ( i != selector_point_ents.end() )
                        {
                                if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
                                        ( *i ).second->setSelected( !wasSelected );
@@ -3006,8 +3305,34 @@ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const
                        }
                        return !wasSelected;
                }
-               else{
-                       return true;
+               else{//do primitives, if ents failed
+                       if ( face ){
+                               Scene_TestSelect_Component( selector, volume, scissored, eFace );
+                       }
+                       else{
+                               Scene_TestSelect( selector, volume, scissored, g_bAltDragManipulatorResize ? ePrimitive : Mode(), ComponentMode() );
+                       }
+                       if ( !selector.failed() ){
+                               SelectableSortedSet::iterator best = selector.begin();
+                               const bool wasSelected = ( *best ).second->isSelected();
+                               ( *best ).second->setSelected( !wasSelected );
+                               SelectableSortedSet::iterator i = best;
+                               ++i;
+                               while ( i != selector.end() )
+                               {
+                                       if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
+                                               ( *i ).second->setSelected( !wasSelected );
+                                       }
+                                       else{
+                                               break;
+                                       }
+                                       ++i;
+                               }
+                               return !wasSelected;
+                       }
+                       else{
+                               return true;
+                       }
                }
        }
 }
@@ -3109,7 +3434,12 @@ void outputScale( TextOutputStream& ostream ){
        ostream << " -scale " << m_scale.x() << " " << m_scale.y() << " " << m_scale.z();
 }
 
-void rotateSelected( const Quaternion& rotation ){
+void rotateSelected( const Quaternion& rotation, bool snapOrigin ){
+       if( snapOrigin && !m_pivotIsCustom ){
+               m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() );
+               m_pivot2world.ty() = float_snapped( m_pivot2world.ty(), GetSnapGridSize() );
+               m_pivot2world.tz() = float_snapped( m_pivot2world.tz(), GetSnapGridSize() );
+       }
        startMove();
        rotate( rotation );
        freezeTransforms();
@@ -3125,7 +3455,7 @@ void scaleSelected( const Vector3& scaling ){
        freezeTransforms();
 }
 
-void MoveSelected( const View& view, const float device_point[2] ){
+void MoveSelected( const View& view, const float device_point[2], bool snap, bool snapbbox ){
        if ( m_manipulator->isSelected() ) {
                if ( !m_undo_begun ) {
                        m_undo_begun = true;
@@ -3134,15 +3464,15 @@ void MoveSelected( const View& view, const float device_point[2] ){
 
                Matrix4 device2manip;
                ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() );
-               m_manipulator->GetManipulatable()->Transform( m_manip2pivot_start, device2manip, device_point[0], device_point[1] );
+               m_manipulator->GetManipulatable()->Transform( m_manip2pivot_start, device2manip, device_point[0], device_point[1], snap, snapbbox );
        }
 }
 
 /// \todo Support view-dependent nudge.
 void NudgeManipulator( const Vector3& nudge, const Vector3& view ){
-       if ( ManipulatorMode() == eTranslate || ManipulatorMode() == eDrag ) {
+//     if ( ManipulatorMode() == eTranslate || ManipulatorMode() == eDrag ) {
                translateSelected( nudge );
-       }
+//     }
 }
 
 void endMove();
@@ -3191,7 +3521,7 @@ inline RadiantSelectionSystem& getSelectionSystem(){
 }
 }
 
-
+#include "map.h"
 
 class testselect_entity_visible : public scene::Graph::Walker
 {
@@ -3202,6 +3532,10 @@ testselect_entity_visible( Selector& selector, SelectionTest& test )
        : m_selector( selector ), m_test( test ){
 }
 bool pre( const scene::Path& path, scene::Instance& instance ) const {
+       if( path.top().get_pointer() == Map_GetWorldspawn( g_map ) ||
+               node_is_group( path.top().get() ) ){
+               return false;
+       }
        Selectable* selectable = Instance_getSelectable( instance );
        if ( selectable != 0
                 && Node_isEntity( path.top() ) ) {
@@ -3349,7 +3683,13 @@ void RadiantSelectionSystem::endMove(){
 
        if ( Mode() == ePrimitive ) {
                if ( ManipulatorMode() == eDrag ) {
-                       Scene_SelectAll_Component( false, SelectionSystem::eFace );
+                       g_bTmpComponentMode = false;
+                       if( g_bAltDragManipulatorResize ){
+                               Scene_SelectAll_Component( false, SelectionSystem::eVertex );
+                       }
+                       else{
+                               Scene_SelectAll_Component( false, SelectionSystem::eFace );
+                       }
                }
        }
 
@@ -3522,11 +3862,6 @@ void RadiantSelectionSystem::ConstructPivot() const {
 }
 
 void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const {
-       /*if ( !m_pivotChanged || m_pivot_moving ) {
-               return;
-       }*/
-       //m_pivotChanged = false;
-
        if ( !nothingSelected() && ( m_manipulator_mode == eTranslate || m_manipulator_mode == eRotate || m_manipulator_mode == eScale ) ) {
                AABB bounds;
                if ( Mode() == eComponent ) {
@@ -3537,11 +3872,8 @@ void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const {
                        Scene_BoundsSelected( GlobalSceneGraph(), bounds );
                }
                //globalOutputStream() << point << "\n";
-               const float gridsize = GetSnapGridSize();
-               //const float bbox_epsilon = gridsize / 4.0;
-
                for( std::size_t i = 0; i < 3; i++ ){
-                       if( point[i] < 900000 ){
+                       if( point[i] < 900000.0f ){
                                float bestsnapDist = fabs( bounds.origin[i] - point[i] );
                                float bestsnapTo = bounds.origin[i];
                                float othersnapDist = fabs( bounds.origin[i] + bounds.extents[i] - point[i] );
@@ -3554,20 +3886,13 @@ void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const {
                                        bestsnapDist = othersnapDist;
                                        bestsnapTo = bounds.origin[i] - bounds.extents[i];
                                }
-                               othersnapDist = fabs( float_snapped( point[i], gridsize ) - point[i] );
+                               othersnapDist = fabs( float_snapped( point[i], GetSnapGridSize() ) - point[i] );
                                if( othersnapDist < bestsnapDist ){
                                        bestsnapDist = othersnapDist;
-                                       bestsnapTo = float_snapped( point[i], gridsize );
+                                       bestsnapTo = float_snapped( point[i], GetSnapGridSize() );
                                }
                                point[i] = bestsnapTo;
 
-/*                             if( float_equal_epsilon( point[i], bestsnapTo, bbox_epsilon ) ){
-                                       point[i] = bestsnapTo;
-                               }
-                               else{
-                                       point[i] = float_snapped( point[i], gridsize );
-                               }
-                               */
                                m_pivot2world[i + 12] = point[i]; //m_pivot2world.tx() .ty() .tz()
                        }
                }
@@ -3597,13 +3922,15 @@ void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const {
                default:
                        break;
                }
+
+               m_pivotIsCustom = true;
        }
-       m_pivotIsCustom = true;
 }
 
-void RadiantSelectionSystem::getSelectionAABB( AABB& bounds ) const {
+AABB RadiantSelectionSystem::getSelectionAABB() const {
+       AABB bounds;
        if ( !nothingSelected() ) {
-               if ( Mode() == eComponent ) {
+               if ( Mode() == eComponent || g_bTmpComponentMode ) {
                        Scene_BoundsSelectedComponent( GlobalSceneGraph(), bounds );
                }
                else
@@ -3611,14 +3938,7 @@ void RadiantSelectionSystem::getSelectionAABB( AABB& bounds ) const {
                        Scene_BoundsSelected( GlobalSceneGraph(), bounds );
                }
        }
-}
-
-void GetSelectionAABB( AABB& bounds ){
-       getSelectionSystem().getSelectionAABB( bounds );
-}
-
-const Matrix4& ssGetPivot2World(){
-       return getSelectionSystem().GetPivot2World();
+       return bounds;
 }
 
 void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
@@ -3640,12 +3960,29 @@ void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest&
 #endif
 }
 
+#include "preferencesystem.h"
+#include "preferences.h"
+
+bool g_bLeftMouseClickSelector = true;
+
+void SelectionSystem_constructPreferences( PreferencesPage& page ){
+       page.appendCheckBox( "", "Prefer point entities in 2D", getSelectionSystem().m_bPreferPointEntsIn2D );
+       page.appendCheckBox( "", "Left mouse click tunnel selector", g_bLeftMouseClickSelector );
+}
+void SelectionSystem_constructPage( PreferenceGroup& group ){
+       PreferencesPage page( group.createPage( "Selection", "Selection System Settings" ) );
+       SelectionSystem_constructPreferences( page );
+}
+void SelectionSystem_registerPreferencesPage(){
+       PreferencesDialog_addSettingsPage( FreeCaller<void(PreferenceGroup&), SelectionSystem_constructPage>() );
+}
+
+
 
 void SelectionSystem_OnBoundsChanged(){
        getSelectionSystem().pivotChanged();
 }
 
-
 SignalHandlerId SelectionSystem_boundsChanged;
 
 void SelectionSystem_Construct(){
@@ -3656,6 +3993,10 @@ void SelectionSystem_Construct(){
        SelectionSystem_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback( FreeCaller<void(), SelectionSystem_OnBoundsChanged>() );
 
        GlobalShaderCache().attachRenderable( getSelectionSystem() );
+
+       GlobalPreferenceSystem().registerPreference( "PreferPointEntsIn2D", make_property_string( getSelectionSystem().m_bPreferPointEntsIn2D ) );
+       GlobalPreferenceSystem().registerPreference( "LeftMouseClickSelector", make_property_string( g_bLeftMouseClickSelector ) );
+       SelectionSystem_registerPreferencesPage();
 }
 
 void SelectionSystem_Destroy(){
@@ -3728,7 +4069,7 @@ const ModifierFlags c_modifier_copy_texture = c_modifierNone;
 class Selector_
 {
 RadiantSelectionSystem::EModifier modifier_for_state( ModifierFlags state ){
-       if ( ( state == c_modifier_toggle || state == c_modifier_toggle_face || state == c_modifier_face ) ) {
+       if ( ( state == c_modifier_toggle || state == c_modifier_toggle_face || state == c_modifier_face || state == c_modifierAlt ) ) {
                if( m_mouse2 ){
                        return RadiantSelectionSystem::eReplace;
                }
@@ -3798,7 +4139,9 @@ void testSelect_simpleM1( DeviceVector position ){
                modifier = RadiantSelectionSystem::eCycle;
        }
        getSelectionSystem().SelectPoint( *m_view, &position[0], &m_epsilon[0], modifier, false );*/
-       getSelectionSystem().SelectPoint( *m_view, &position[0], &m_epsilon[0], m_mouseMoved ? RadiantSelectionSystem::eReplace : RadiantSelectionSystem::eCycle, false );
+       if( g_bLeftMouseClickSelector ){
+               getSelectionSystem().SelectPoint( *m_view, &position[0], &m_epsilon[0], m_mouseMoved ? RadiantSelectionSystem::eReplace : RadiantSelectionSystem::eCycle, false );
+       }
        m_start = m_current = device_constrained( position );
 }
 
@@ -3867,13 +4210,17 @@ class Manipulator_
 public:
 DeviceVector m_epsilon;
 const View* m_view;
+ModifierFlags m_state;
+
+Manipulator_() : m_state( c_modifierNone ){
+}
 
 bool mouseDown( DeviceVector position ){
        return getSelectionSystem().SelectManipulator( *m_view, &position[0], &m_epsilon[0] );
 }
 
 void mouseMoved( DeviceVector position ){
-       getSelectionSystem().MoveSelected( *m_view, &position[0] );
+       getSelectionSystem().MoveSelected( *m_view, &position[0], ( m_state & c_modifierShift ) == c_modifierShift, ( m_state & c_modifierControl ) == c_modifierControl );
 }
 typedef MemberCaller<Manipulator_, void(DeviceVector), &Manipulator_::mouseMoved> MouseMovedCaller;
 
@@ -3883,6 +4230,21 @@ void mouseUp( DeviceVector position ){
        g_mouseUpCallback.clear();
 }
 typedef MemberCaller<Manipulator_, void(DeviceVector), &Manipulator_::mouseUp> MouseUpCaller;
+
+void setState( ModifierFlags state ){
+       m_state = state;
+}
+
+ModifierFlags getState() const {
+       return m_state;
+}
+
+void modifierEnable( ModifierFlags type ){
+       setState( bitfield_enable( getState(), type ) );
+}
+void modifierDisable( ModifierFlags type ){
+       setState( bitfield_disable( getState(), type ) );
+}
 };
 
 void Scene_copyClosestTexture( SelectionTest& test );
@@ -3928,18 +4290,14 @@ void onMouseDown( const WindowVector& position, ButtonIdentifier button, Modifie
                //m_selector.m_mouseMoved = false;
 
                DeviceVector devicePosition( window_to_normalised_device( position, m_width, m_height ) );
-               if ( modifiers == c_modifier_manipulator && m_manipulator.mouseDown( devicePosition ) ) {
+               g_bAltDragManipulatorResize = ( modifiers == c_modifierAlt ) ? true : false;
+               if ( ( modifiers == c_modifier_manipulator || ( modifiers == c_modifierAlt && getSelectionSystem().Mode() != SelectionSystem::eComponent ) ) && m_manipulator.mouseDown( devicePosition ) ) {
                        g_mouseMovedCallback.insert( MouseEventCallback( Manipulator_::MouseMovedCaller( m_manipulator ) ) );
                        g_mouseUpCallback.insert( MouseEventCallback( Manipulator_::MouseUpCaller( m_manipulator ) ) );
                }
                else
                {
-                       if ( button == c_button_select ) {
-                               m_selector.m_mouse2 = false;
-                       }
-                       else{
-                               m_selector.m_mouse2 = true;
-                       }
+                       m_selector.m_mouse2 = ( button == c_button_select ) ? false : true;
                        m_selector.mouseDown( devicePosition );
                        g_mouseMovedCallback.insert( MouseEventCallback( Selector_::MouseMovedCaller( m_selector ) ) );
                        g_mouseUpCallback.insert( MouseEventCallback( Selector_::MouseUpCaller( m_selector ) ) );
@@ -3987,9 +4345,11 @@ void onMouseUp( const WindowVector& position, ButtonIdentifier button, ModifierF
 }
 void onModifierDown( ModifierFlags type ){
        m_selector.modifierEnable( type );
+       m_manipulator.modifierEnable( type );
 }
 void onModifierUp( ModifierFlags type ){
        m_selector.modifierDisable( type );
+       m_manipulator.modifierDisable( type );
 }
 };