]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/select.cpp
Merge branch 'illwieckz/vfs' fix !101
[xonotic/netradiant.git] / radiant / select.cpp
index 70e815d138acc9526ac281fe1cc46c36f8bd79b8..578124c73089c93b651a1edb93a688c2641aefce 100644 (file)
@@ -1,26 +1,28 @@
 /*
-Copyright (C) 1999-2006 Id Software, Inc. and contributors.
-For a list of contributors, see the accompanying CONTRIBUTORS file.
+   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
 
-This file is part of GtkRadiant.
+   This file is part of GtkRadiant.
 
-GtkRadiant is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-GtkRadiant is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GtkRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GtkRadiant; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 #include "select.h"
 
+#include <gtk/gtk.h>
+
 #include "debugging/debugging.h"
 
 #include "ientity.h"
@@ -47,1168 +49,1137 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "mainframe.h"
 #include "grid.h"
 #include "map.h"
-
+#include "entityinspector.h"
 
 
 select_workzone_t g_select_workzone;
 
 
 /**
-  Loops over all selected brushes and stores their
-  world AABBs in the specified array.
-*/
-class CollectSelectedBrushesBounds : public SelectionSystem::Visitor
-{
-  AABB* m_bounds;   // array of AABBs
-  Unsigned m_max;   // max AABB-elements in array
-  Unsigned& m_count;// count of valid AABBs stored in array
+   Loops over all selected brushes and stores their
+   world AABBs in the specified array.
+ */
+class CollectSelectedBrushesBounds : public SelectionSystem::Visitor {
+    AABB *m_bounds;     // array of AABBs
+    Unsigned m_max;     // max AABB-elements in array
+    Unsigned &m_count;  // count of valid AABBs stored in array
 
 public:
-  CollectSelectedBrushesBounds(AABB* bounds, Unsigned max, Unsigned& count)
-    : m_bounds(bounds),
-      m_max(max),
-      m_count(count)
-  {
-    m_count = 0;
-  }
-
-  void visit(scene::Instance& instance) const
-  {
-    ASSERT_MESSAGE(m_count <= m_max, "Invalid m_count in CollectSelectedBrushesBounds");
-
-    // stop if the array is already full
-    if(m_count == m_max)
-      return;
-
-    Selectable* selectable = Instance_getSelectable(instance);
-    if((selectable != 0)
-      && instance.isSelected())
+    CollectSelectedBrushesBounds(AABB *bounds, Unsigned max, Unsigned &count)
+            : m_bounds(bounds),
+              m_max(max),
+              m_count(count)
     {
-      // brushes only
-      if(Instance_getBrush(instance) != 0)
-      {
-        m_bounds[m_count] = instance.worldAABB();
-        ++m_count;
-      }
+        m_count = 0;
+    }
+
+    void visit(scene::Instance &instance) const
+    {
+        ASSERT_MESSAGE(m_count <= m_max, "Invalid m_count in CollectSelectedBrushesBounds");
+
+        // stop if the array is already full
+        if (m_count == m_max) {
+            return;
+        }
+
+        Selectable *selectable = Instance_getSelectable(instance);
+        if ((selectable != 0)
+            && instance.isSelected()) {
+            // brushes only
+            if (Instance_getBrush(instance) != 0) {
+                m_bounds[m_count] = instance.worldAABB();
+                ++m_count;
+            }
+        }
     }
-  }
 };
 
 /**
-  Selects all objects that intersect one of the bounding AABBs.
-  The exact intersection-method is specified through TSelectionPolicy
-*/
+   Selects all objects that intersect one of the bounding AABBs.
+   The exact intersection-method is specified through TSelectionPolicy
+ */
 template<class TSelectionPolicy>
-class SelectByBounds : public scene::Graph::Walker
-{
-  AABB* m_aabbs;           // selection aabbs
-  Unsigned m_count;        // number of aabbs in m_aabbs
-  TSelectionPolicy policy; // type that contains a custom intersection method aabb<->aabb
+class SelectByBounds : public scene::Graph::Walker {
+    AABB *m_aabbs;             // selection aabbs
+    Unsigned m_count;          // number of aabbs in m_aabbs
+    TSelectionPolicy policy;   // type that contains a custom intersection method aabb<->aabb
 
 public:
-  SelectByBounds(AABB* aabbs, Unsigned count)
-      : m_aabbs(aabbs),
-        m_count(count)
-  {
-  }
-
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    Selectable* selectable = Instance_getSelectable(instance);
-
-    // ignore worldspawn
-    Entity* entity = Node_getEntity(path.top());
-    if(entity)
+    SelectByBounds(AABB *aabbs, Unsigned count)
+            : m_aabbs(aabbs),
+              m_count(count)
     {
-      if(string_equal(entity->getKeyValue("classname"), "worldspawn"))
-        return true;
     }
-    
-    if( (path.size() > 1) &&
-        (!path.top().get().isRoot()) &&
-        (selectable != 0)
-       )
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
     {
-      for(Unsigned i = 0; i < m_count; ++i)
-      {
-        if(policy.Evaluate(m_aabbs[i], instance))
-        {
-          selectable->setSelected(true);
+        Selectable *selectable = Instance_getSelectable(instance);
+
+        // ignore worldspawn
+        Entity *entity = Node_getEntity(path.top());
+        if (entity) {
+            if (string_equal(entity->getKeyValue("classname"), "worldspawn")) {
+                return true;
+            }
+        }
+
+        if ((path.size() > 1) &&
+            (!path.top().get().isRoot()) &&
+            (selectable != 0)
+                ) {
+            for (Unsigned i = 0; i < m_count; ++i) {
+                if (policy.Evaluate(m_aabbs[i], instance)) {
+                    selectable->setSelected(true);
+                }
+            }
         }
-      }
+
+        return true;
     }
 
-    return true;
-  }
-
-  /**
-    Performs selection operation on the global scenegraph.
-    If delete_bounds_src is true, then the objects which were
-    used as source for the selection aabbs will be deleted.
-*/
-  static void DoSelection(bool delete_bounds_src = true)
-  {
-    if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
+/**
+   Performs selection operation on the global scenegraph.
+   If delete_bounds_src is true, then the objects which were
+   used as source for the selection aabbs will be deleted.
+ */
+    static void DoSelection(bool delete_bounds_src = true)
     {
-      // we may not need all AABBs since not all selected objects have to be brushes
-      const Unsigned max = (Unsigned)GlobalSelectionSystem().countSelected();
-      AABB* aabbs = new AABB[max];
-            
-      Unsigned count;
-      CollectSelectedBrushesBounds collector(aabbs, max, count);
-      GlobalSelectionSystem().foreachSelected(collector);
-
-      // nothing usable in selection
-      if(!count)
-      {
-        delete[] aabbs;
-        return;
-      }
-      
-      // delete selected objects
-      if(delete_bounds_src)// see deleteSelection
-      {
-        UndoableCommand undo("deleteSelected");
-        Select_Delete();
-      }
-
-      // select objects with bounds
-      GlobalSceneGraph().traverse(SelectByBounds<TSelectionPolicy>(aabbs, count));
-      
-      SceneChangeNotify();
-      delete[] aabbs;
+        if (GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive) {
+            // we may not need all AABBs since not all selected objects have to be brushes
+            const Unsigned max = (Unsigned) GlobalSelectionSystem().countSelected();
+            AABB *aabbs = new AABB[max];
+
+            Unsigned count;
+            CollectSelectedBrushesBounds collector(aabbs, max, count);
+            GlobalSelectionSystem().foreachSelected(collector);
+
+            // nothing usable in selection
+            if (!count) {
+                delete[] aabbs;
+                return;
+            }
+
+            // delete selected objects
+            if (delete_bounds_src) { // see deleteSelection
+                UndoableCommand undo("deleteSelected");
+                Select_Delete();
+            }
+
+            // select objects with bounds
+            GlobalSceneGraph().traverse(SelectByBounds<TSelectionPolicy>(aabbs, count));
+
+            SceneChangeNotify();
+            delete[] aabbs;
+        }
     }
-  }
 };
 
 /**
-  SelectionPolicy for SelectByBounds
-  Returns true if box and the AABB of instance intersect
-*/
-class SelectionPolicy_Touching
-{
+   SelectionPolicy for SelectByBounds
+   Returns true if box and the AABB of instance intersect
+ */
+class SelectionPolicy_Touching {
 public:
-  bool Evaluate(const AABB& box, scene::Instance& instance) const
-  {
-    const AABB& other(instance.worldAABB());
-    for(Unsigned i = 0; i < 3; ++i)
+    bool Evaluate(const AABB &box, scene::Instance &instance) const
     {
-      if(fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] + other.extents[i]))
-        return false;
+        const AABB &other(instance.worldAABB());
+        for (Unsigned i = 0; i < 3; ++i) {
+            if (fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] + other.extents[i])) {
+                return false;
+            }
+        }
+        return true;
     }
-    return true;
-  }
 };
 
 /**
-  SelectionPolicy for SelectByBounds
-  Returns true if the AABB of instance is inside box
-*/
-class SelectionPolicy_Inside
-{
+   SelectionPolicy for SelectByBounds
+   Returns true if the AABB of instance is inside box
+ */
+class SelectionPolicy_Inside {
 public:
-  bool Evaluate(const AABB& box, scene::Instance& instance) const
-  {
-    const AABB& other(instance.worldAABB());
-    for(Unsigned i = 0; i < 3; ++i)
+    bool Evaluate(const AABB &box, scene::Instance &instance) const
     {
-      if(fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] - other.extents[i]))
-        return false;
+        const AABB &other(instance.worldAABB());
+        for (Unsigned i = 0; i < 3; ++i) {
+            if (fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] - other.extents[i])) {
+                return false;
+            }
+        }
+        return true;
     }
-    return true;
-  }
 };
 
-class DeleteSelected : public scene::Graph::Walker
-{
-  mutable bool m_remove;
-  mutable bool m_removedChild;
+class DeleteSelected : public scene::Graph::Walker {
+    mutable bool m_remove;
+    mutable bool m_removedChild;
 public:
-  DeleteSelected()
-    : m_remove(false), m_removedChild(false)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    m_removedChild = false;
-
-    Selectable* selectable = Instance_getSelectable(instance);
-    if(selectable != 0
-      && selectable->isSelected()
-      && path.size() > 1
-      && !path.top().get().isRoot())
+    DeleteSelected()
+            : m_remove(false), m_removedChild(false)
     {
-      m_remove = true;
-
-      return false;// dont traverse into child elements
     }
-    return true;
-  }
-  void post(const scene::Path& path, scene::Instance& instance) const
-  {
-    
-    if(m_removedChild)
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
     {
-      m_removedChild = false;
-
-      // delete empty entities
-      Entity* entity = Node_getEntity(path.top());
-      if(entity != 0
-        && path.top().get_pointer() != Map_FindWorldspawn(g_map)
-        && Node_getTraversable(path.top())->empty())
-      {
-        Path_deleteTop(path);
-      }
+        m_removedChild = false;
+
+        Selectable *selectable = Instance_getSelectable(instance);
+        if (selectable != 0
+            && selectable->isSelected()
+            && path.size() > 1
+            && !path.top().get().isRoot()) {
+            m_remove = true;
+
+            return false; // dont traverse into child elements
+        }
+        return true;
     }
 
-       // node should be removed
-    if(m_remove)
+    void post(const scene::Path &path, scene::Instance &instance) const
     {
-      if(Node_isEntity(path.parent()) != 0)
-      {
-        m_removedChild = true;
-      }
 
-      m_remove = false;
-      Path_deleteTop(path);
+        if (m_removedChild) {
+            m_removedChild = false;
+
+            // delete empty entities
+            Entity *entity = Node_getEntity(path.top());
+            if (entity != 0
+                && path.top().get_pointer() != Map_FindWorldspawn(g_map)
+                && Node_getTraversable(path.top())->empty()) {
+                Path_deleteTop(path);
+            }
+        }
+
+        // node should be removed
+        if (m_remove) {
+            if (Node_isEntity(path.parent()) != 0) {
+                m_removedChild = true;
+            }
+
+            m_remove = false;
+            Path_deleteTop(path);
+        }
     }
-  }
 };
 
-void Scene_DeleteSelected(scene::Graphgraph)
+void Scene_DeleteSelected(scene::Graph &graph)
 {
-  graph.traverse(DeleteSelected());
-  SceneChangeNotify();
+    graph.traverse(DeleteSelected());
+    SceneChangeNotify();
 }
 
-void Select_Delete (void)
+void Select_Delete(void)
 {
-  Scene_DeleteSelected(GlobalSceneGraph());
+    Scene_DeleteSelected(GlobalSceneGraph());
 }
 
-class InvertSelectionWalker : public scene::Graph::Walker
-{
-  SelectionSystem::EMode m_mode;
-  mutable Selectable* m_selectable;
+class InvertSelectionWalker : public scene::Graph::Walker {
+    SelectionSystem::EMode m_mode;
+    mutable Selectable *m_selectable;
 public:
-  InvertSelectionWalker(SelectionSystem::EMode mode)
-    : m_mode(mode), m_selectable(0)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    Selectable* selectable = Instance_getSelectable(instance);
-    if(selectable)
+    InvertSelectionWalker(SelectionSystem::EMode mode)
+            : m_mode(mode), m_selectable(0)
     {
-      switch(m_mode)
-      {
-      case SelectionSystem::eEntity:
-        if(Node_isEntity(path.top()) != 0)
-        {
-          m_selectable = path.top().get().visible() ? selectable : 0;
+    }
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
+    {
+        Selectable *selectable = Instance_getSelectable(instance);
+        if (selectable) {
+            switch (m_mode) {
+                case SelectionSystem::eEntity:
+                    if (Node_isEntity(path.top()) != 0) {
+                        m_selectable = path.top().get().visible() ? selectable : 0;
+                    }
+                    break;
+                case SelectionSystem::ePrimitive:
+                    m_selectable = path.top().get().visible() ? selectable : 0;
+                    break;
+                case SelectionSystem::eComponent:
+                    break;
+            }
         }
-        break;
-      case SelectionSystem::ePrimitive:
-        m_selectable = path.top().get().visible() ? selectable : 0;
-        break;
-      case SelectionSystem::eComponent:
-        break;
-      }
+        return true;
     }
-    return true;
-  }
-  void post(const scene::Path& path, scene::Instance& instance) const
-  {
-    if(m_selectable != 0)
+
+    void post(const scene::Path &path, scene::Instance &instance) const
     {
-      m_selectable->setSelected(!m_selectable->isSelected());
-      m_selectable = 0;
+        if (m_selectable != 0) {
+            m_selectable->setSelected(!m_selectable->isSelected());
+            m_selectable = 0;
+        }
     }
-  }
 };
 
-void Scene_Invert_Selection(scene::Graphgraph)
+void Scene_Invert_Selection(scene::Graph &graph)
 {
-  graph.traverse(InvertSelectionWalker(GlobalSelectionSystem().Mode()));
+    graph.traverse(InvertSelectionWalker(GlobalSelectionSystem().Mode()));
 }
 
 void Select_Invert()
 {
-  Scene_Invert_Selection(GlobalSceneGraph());
+    Scene_Invert_Selection(GlobalSceneGraph());
 }
 
-class ExpandSelectionToEntitiesWalker : public scene::Graph::Walker
-{
-  mutable std::size_t m_depth;
+class ExpandSelectionToEntitiesWalker : public scene::Graph::Walker {
+    mutable std::size_t m_depth;
+    NodeSmartReference worldspawn;
 public:
-  ExpandSelectionToEntitiesWalker() : m_depth(0)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    ++m_depth;
-    if(m_depth == 2) // entity depth
+    ExpandSelectionToEntitiesWalker() : m_depth(0), worldspawn(Map_FindOrInsertWorldspawn(g_map))
     {
-      // traverse and select children if any one is selected
-      return Node_getEntity(path.top())->isContainer() && instance.childSelected();
     }
-    else if(m_depth == 3) // primitive depth
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
     {
-      Instance_setSelected(instance, true);
-      return false;
+        ++m_depth;
+
+        // ignore worldspawn
+        NodeSmartReference me(path.top().get());
+        if (me == worldspawn) {
+            return false;
+        }
+
+        if (m_depth == 2) { // entity depth
+            // traverse and select children if any one is selected
+            if (instance.childSelected()) {
+                Instance_setSelected(instance, true);
+            }
+            return Node_getEntity(path.top())->isContainer() && instance.isSelected();
+        } else if (m_depth == 3) { // primitive depth
+            Instance_setSelected(instance, true);
+            return false;
+        }
+        return true;
+    }
+
+    void post(const scene::Path &path, scene::Instance &instance) const
+    {
+        --m_depth;
     }
-    return true;
-  }
-  void post(const scene::Path& path, scene::Instance& instance) const
-  {
-    --m_depth;
-  }
 };
 
 void Scene_ExpandSelectionToEntities()
 {
-  GlobalSceneGraph().traverse(ExpandSelectionToEntitiesWalker());
+    GlobalSceneGraph().traverse(ExpandSelectionToEntitiesWalker());
 }
 
 
-namespace
-{
-  void Selection_UpdateWorkzone()
-  {
-    if(GlobalSelectionSystem().countSelected() != 0)
+namespace {
+    void Selection_UpdateWorkzone()
     {
-      Select_GetBounds(g_select_workzone.d_work_min, g_select_workzone.d_work_max);
+        if (GlobalSelectionSystem().countSelected() != 0) {
+            Select_GetBounds(g_select_workzone.d_work_min, g_select_workzone.d_work_max);
+        }
     }
-  }
-  typedef FreeCaller<Selection_UpdateWorkzone> SelectionUpdateWorkzoneCaller;
 
-  IdleDraw g_idleWorkzone = IdleDraw(SelectionUpdateWorkzoneCaller());
+    typedef FreeCaller<void(), Selection_UpdateWorkzone> SelectionUpdateWorkzoneCaller;
+
+    IdleDraw g_idleWorkzone = IdleDraw(SelectionUpdateWorkzoneCaller());
 }
 
-const select_workzone_tSelect_getWorkZone()
+const select_workzone_t &Select_getWorkZone()
 {
-  g_idleWorkzone.flush();
-  return g_select_workzone;
+    g_idleWorkzone.flush();
+    return g_select_workzone;
 }
 
 void UpdateWorkzone_ForSelection()
 {
-  g_idleWorkzone.queueDraw();
+    g_idleWorkzone.queueDraw();
 }
 
 // update the workzone to the current selection
-void UpdateWorkzone_ForSelectionChanged(const Selectableselectable)
+void UpdateWorkzone_ForSelectionChanged(const Selectable &selectable)
 {
-  if(selectable.isSelected())
-  {
-    UpdateWorkzone_ForSelection();
-  }
+    if (selectable.isSelected()) {
+        UpdateWorkzone_ForSelection();
+    }
 }
 
-void Select_SetShader(const charshader)
+void Select_SetShader(const char *shader)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushSetShader_Selected(GlobalSceneGraph(), shader);
-    Scene_PatchSetShader_Selected(GlobalSceneGraph(), shader);
-  }
-  Scene_BrushSetShader_Component_Selected(GlobalSceneGraph(), shader);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushSetShader_Selected(GlobalSceneGraph(), shader);
+        Scene_PatchSetShader_Selected(GlobalSceneGraph(), shader);
+    }
+    Scene_BrushSetShader_Component_Selected(GlobalSceneGraph(), shader);
 }
 
-void Select_SetTexdef(const TextureProjectionprojection)
+void Select_SetTexdef(const TextureProjection &projection)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushSetTexdef_Selected(GlobalSceneGraph(), projection);
-  }
-  Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushSetTexdef_Selected(GlobalSceneGraph(), projection);
+    }
+    Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection);
 }
 
-void Select_SetFlags(const ContentsFlagsValueflags)
+void Select_SetFlags(const ContentsFlagsValue &flags)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushSetFlags_Selected(GlobalSceneGraph(), flags);
-  }
-  Scene_BrushSetFlags_Component_Selected(GlobalSceneGraph(), flags);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushSetFlags_Selected(GlobalSceneGraph(), flags);
+    }
+    Scene_BrushSetFlags_Component_Selected(GlobalSceneGraph(), flags);
 }
 
-void Select_GetBounds (Vector3& mins, Vector3& maxs)
+void Select_GetBounds(Vector3 &mins, Vector3 &maxs)
 {
-  AABB bounds;
-  Scene_BoundsSelected(GlobalSceneGraph(), bounds);
-  maxs = vector3_added(bounds.origin, bounds.extents);
-  mins = vector3_subtracted(bounds.origin, bounds.extents);
+    AABB bounds;
+    Scene_BoundsSelected(GlobalSceneGraph(), bounds);
+    maxs = vector3_added(bounds.origin, bounds.extents);
+    mins = vector3_subtracted(bounds.origin, bounds.extents);
 }
 
-void Select_GetMid (Vector3& mid)
+void Select_GetMid(Vector3 &mid)
 {
-  AABB bounds;
-  Scene_BoundsSelected(GlobalSceneGraph(), bounds);
-  mid = vector3_snapped(bounds.origin);
+    AABB bounds;
+    Scene_BoundsSelected(GlobalSceneGraph(), bounds);
+    mid = vector3_snapped(bounds.origin);
 }
 
 
-void Select_FlipAxis (int axis)
+void Select_FlipAxis(int axis)
 {
-  Vector3 flip(1, 1, 1);
-  flip[axis] = -1;
-  GlobalSelectionSystem().scaleSelected(flip);
+    Vector3 flip(1, 1, 1);
+    flip[axis] = -1;
+    GlobalSelectionSystem().scaleSelected(flip);
 }
 
 
 void Select_Scale(float x, float y, float z)
 {
-  GlobalSelectionSystem().scaleSelected(Vector3(x, y, z));
+    GlobalSelectionSystem().scaleSelected(Vector3(x, y, z));
 }
 
-enum axis_t
-{
-  eAxisX = 0,
-  eAxisY = 1,
-  eAxisZ = 2,
+enum axis_t {
+    eAxisX = 0,
+    eAxisY = 1,
+    eAxisZ = 2,
 };
 
-enum sign_t
-{
-  eSignPositive = 1,
-  eSignNegative = -1,
+enum sign_t {
+    eSignPositive = 1,
+    eSignNegative = -1,
 };
 
 inline Matrix4 matrix4_rotation_for_axis90(axis_t axis, sign_t sign)
 {
-  switch(axis)
-  {
-  case eAxisX:
-    if(sign == eSignPositive)
-    {
-      return matrix4_rotation_for_sincos_x(1, 0);
-    }
-    else
-    {
-      return matrix4_rotation_for_sincos_x(-1, 0);
-    }
-  case eAxisY:
-    if(sign == eSignPositive)
-    {
-      return matrix4_rotation_for_sincos_y(1, 0);
-    }
-    else
-    {
-      return matrix4_rotation_for_sincos_y(-1, 0);
+    switch (axis) {
+        case eAxisX:
+            if (sign == eSignPositive) {
+                return matrix4_rotation_for_sincos_x(1, 0);
+            } else {
+                return matrix4_rotation_for_sincos_x(-1, 0);
+            }
+        case eAxisY:
+            if (sign == eSignPositive) {
+                return matrix4_rotation_for_sincos_y(1, 0);
+            } else {
+                return matrix4_rotation_for_sincos_y(-1, 0);
+            }
+        default: //case eAxisZ:
+            if (sign == eSignPositive) {
+                return matrix4_rotation_for_sincos_z(1, 0);
+            } else {
+                return matrix4_rotation_for_sincos_z(-1, 0);
+            }
     }
-  default://case eAxisZ:
-    if(sign == eSignPositive)
-    {
-      return matrix4_rotation_for_sincos_z(1, 0);
-    }
-    else
-    {
-      return matrix4_rotation_for_sincos_z(-1, 0);
-    }
-  }
 }
 
-inline void matrix4_rotate_by_axis90(Matrix4matrix, axis_t axis, sign_t sign)
+inline void matrix4_rotate_by_axis90(Matrix4 &matrix, axis_t axis, sign_t sign)
 {
-  matrix4_multiply_by_matrix4(matrix, matrix4_rotation_for_axis90(axis, sign));
+    matrix4_multiply_by_matrix4(matrix, matrix4_rotation_for_axis90(axis, sign));
 }
 
-inline void matrix4_pivoted_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign, const Vector3& pivotpoint)
+inline void matrix4_pivoted_rotate_by_axis90(Matrix4 &matrix, axis_t axis, sign_t sign, const Vector3 &pivotpoint)
 {
-  matrix4_translate_by_vec3(matrix, pivotpoint);
-  matrix4_rotate_by_axis90(matrix, axis, sign);
-  matrix4_translate_by_vec3(matrix, vector3_negated(pivotpoint));
+    matrix4_translate_by_vec3(matrix, pivotpoint);
+    matrix4_rotate_by_axis90(matrix, axis, sign);
+    matrix4_translate_by_vec3(matrix, vector3_negated(pivotpoint));
 }
 
 inline Quaternion quaternion_for_axis90(axis_t axis, sign_t sign)
 {
 #if 1
-  switch(axis)
-  {
-  case eAxisX:
-    if(sign == eSignPositive)
-    {
-      return Quaternion(c_half_sqrt2f, 0, 0, c_half_sqrt2f);
-    }
-    else
-    {
-      return Quaternion(-c_half_sqrt2f, 0, 0, -c_half_sqrt2f);
-    }
-  case eAxisY:
-    if(sign == eSignPositive)
-    {
-      return Quaternion(0, c_half_sqrt2f, 0, c_half_sqrt2f);
-    }
-    else
-    {
-      return Quaternion(0, -c_half_sqrt2f, 0, -c_half_sqrt2f);
-    }
-  default://case eAxisZ:
-    if(sign == eSignPositive)
-    {
-      return Quaternion(0, 0, c_half_sqrt2f, c_half_sqrt2f);
-    }
-    else
-    {
-      return Quaternion(0, 0, -c_half_sqrt2f, -c_half_sqrt2f);
+    switch (axis) {
+        case eAxisX:
+            if (sign == eSignPositive) {
+                return Quaternion(c_half_sqrt2f, 0, 0, c_half_sqrt2f);
+            } else {
+                return Quaternion(-c_half_sqrt2f, 0, 0, -c_half_sqrt2f);
+            }
+        case eAxisY:
+            if (sign == eSignPositive) {
+                return Quaternion(0, c_half_sqrt2f, 0, c_half_sqrt2f);
+            } else {
+                return Quaternion(0, -c_half_sqrt2f, 0, -c_half_sqrt2f);
+            }
+        default: //case eAxisZ:
+            if (sign == eSignPositive) {
+                return Quaternion(0, 0, c_half_sqrt2f, c_half_sqrt2f);
+            } else {
+                return Quaternion(0, 0, -c_half_sqrt2f, -c_half_sqrt2f);
+            }
     }
-  }
 #else
-  quaternion_for_matrix4_rotation(matrix4_rotation_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
+    quaternion_for_matrix4_rotation( matrix4_rotation_for_axis90( (axis_t)axis, ( deg > 0 ) ? eSignPositive : eSignNegative ) );
 #endif
 }
 
-void Select_RotateAxis (int axis, float deg)
-{
-  if(fabs(deg) == 90.f)
-  {
-    GlobalSelectionSystem().rotateSelected(quaternion_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
-  }
-  else
-  {
-    switch(axis)
-    {
-    case 0:
-      GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_x_degrees(deg)));
-      break;
-    case 1:
-      GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_y_degrees(deg)));
-      break;
-    case 2:
-      GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_z_degrees(deg)));
-      break;
+void Select_RotateAxis(int axis, float deg)
+{
+    if (fabs(deg) == 90.f) {
+        GlobalSelectionSystem().rotateSelected(
+                quaternion_for_axis90((axis_t) axis, (deg > 0) ? eSignPositive : eSignNegative));
+    } else {
+        switch (axis) {
+            case 0:
+                GlobalSelectionSystem().rotateSelected(
+                        quaternion_for_matrix4_rotation(matrix4_rotation_for_x_degrees(deg)));
+                break;
+            case 1:
+                GlobalSelectionSystem().rotateSelected(
+                        quaternion_for_matrix4_rotation(matrix4_rotation_for_y_degrees(deg)));
+                break;
+            case 2:
+                GlobalSelectionSystem().rotateSelected(
+                        quaternion_for_matrix4_rotation(matrix4_rotation_for_z_degrees(deg)));
+                break;
+        }
     }
-  }
 }
 
 
 void Select_ShiftTexture(float x, float y)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushShiftTexdef_Selected(GlobalSceneGraph(), x, y);
-    Scene_PatchTranslateTexture_Selected(GlobalSceneGraph(), x, y);
-  }
-  //globalOutputStream() << "shift selected face textures: s=" << x << " t=" << y << '\n';
-  Scene_BrushShiftTexdef_Component_Selected(GlobalSceneGraph(), x, y);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushShiftTexdef_Selected(GlobalSceneGraph(), x, y);
+        Scene_PatchTranslateTexture_Selected(GlobalSceneGraph(), x, y);
+    }
+    //globalOutputStream() << "shift selected face textures: s=" << x << " t=" << y << '\n';
+    Scene_BrushShiftTexdef_Component_Selected(GlobalSceneGraph(), x, y);
 }
 
 void Select_ScaleTexture(float x, float y)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushScaleTexdef_Selected(GlobalSceneGraph(), x, y);
-    Scene_PatchScaleTexture_Selected(GlobalSceneGraph(), x, y);
-  }
-  Scene_BrushScaleTexdef_Component_Selected(GlobalSceneGraph(), x, y);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushScaleTexdef_Selected(GlobalSceneGraph(), x, y);
+        Scene_PatchScaleTexture_Selected(GlobalSceneGraph(), x, y);
+    }
+    Scene_BrushScaleTexdef_Component_Selected(GlobalSceneGraph(), x, y);
 }
 
 void Select_RotateTexture(float amt)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushRotateTexdef_Selected(GlobalSceneGraph(), amt);
-    Scene_PatchRotateTexture_Selected(GlobalSceneGraph(), amt);
-  }
-  Scene_BrushRotateTexdef_Component_Selected(GlobalSceneGraph(), amt);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushRotateTexdef_Selected(GlobalSceneGraph(), amt);
+        Scene_PatchRotateTexture_Selected(GlobalSceneGraph(), amt);
+    }
+    Scene_BrushRotateTexdef_Component_Selected(GlobalSceneGraph(), amt);
 }
 
 // TTimo modified to handle shader architecture:
 // expects shader names at input, comparison relies on shader names .. texture names no longer relevant
-void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected)
+void FindReplaceTextures(const char *pFind, const char *pReplace, bool bSelected)
 {
-  if(!texdef_name_valid(pFind))
-  {
-    globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pFind << "', aborted\n";
-    return;
-  }
-  if(!texdef_name_valid(pReplace))
-  {
-    globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pReplace << "', aborted\n";
-    return;
-  }
-
-  StringOutputStream command;
-  command << "textureFindReplace -find " << pFind << " -replace " << pReplace;
-  UndoableCommand undo(command.c_str());
-
-  if(bSelected)
-  {
-    if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-    {
-      Scene_BrushFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
-      Scene_PatchFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
+    if (!texdef_name_valid(pFind)) {
+        globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pFind << "', aborted\n";
+        return;
+    }
+    if (!texdef_name_valid(pReplace)) {
+        globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pReplace << "', aborted\n";
+        return;
+    }
+
+    StringOutputStream command;
+    command << "textureFindReplace -find " << pFind << " -replace " << pReplace;
+    UndoableCommand undo(command.c_str());
+
+    if (bSelected) {
+        if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+            Scene_BrushFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
+            Scene_PatchFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
+        }
+        Scene_BrushFindReplaceShader_Component_Selected(GlobalSceneGraph(), pFind, pReplace);
+    } else {
+        Scene_BrushFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
+        Scene_PatchFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
     }
-    Scene_BrushFindReplaceShader_Component_Selected(GlobalSceneGraph(), pFind, pReplace);
-  }
-  else
-  {
-    Scene_BrushFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
-    Scene_PatchFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
-  }
 }
 
-typedef std::vector<const char*> Classnames;
+typedef std::vector<const char *> PropertyValues;
 
-bool classnames_match_entity(const Classnames& classnames, Entity* entity)
+bool propertyvalues_contain(const PropertyValues &propertyvalues, const char *str)
 {
-  for(Classnames::const_iterator i = classnames.begin(); i != classnames.end(); ++i)
-  {
-    if(string_equal(entity->getKeyValue("classname"), *i))
-    {
-      return true;
+    for (PropertyValues::const_iterator i = propertyvalues.begin(); i != propertyvalues.end(); ++i) {
+        if (string_equal(str, *i)) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-class EntityFindByClassnameWalker : public scene::Graph::Walker
-{
-  const Classnames& m_classnames;
+class EntityFindByPropertyValueWalker : public scene::Graph::Walker {
+    const PropertyValues &m_propertyvalues;
+    const char *m_prop;
 public:
-  EntityFindByClassnameWalker(const Classnames& classnames)
-    : m_classnames(classnames)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    Entity* entity = Node_getEntity(path.top());
-    if(entity != 0
-      && classnames_match_entity(m_classnames, entity))
+    EntityFindByPropertyValueWalker(const char *prop, const PropertyValues &propertyvalues)
+            : m_propertyvalues(propertyvalues), m_prop(prop)
+    {
+    }
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
     {
-      Instance_getSelectable(instance)->setSelected(true);
+        Entity *entity = Node_getEntity(path.top());
+        if (entity != 0
+            && propertyvalues_contain(m_propertyvalues, entity->getKeyValue(m_prop))) {
+            Instance_getSelectable(instance)->setSelected(true);
+        }
+        return true;
     }
-    return true;
-  }
 };
 
-void Scene_EntitySelectByClassnames(scene::Graph& graph, const Classnames& classnames)
+void Scene_EntitySelectByPropertyValues(scene::Graph &graph, const char *prop, const PropertyValues &propertyvalues)
 {
-  graph.traverse(EntityFindByClassnameWalker(classnames));
+    graph.traverse(EntityFindByPropertyValueWalker(prop, propertyvalues));
 }
 
-class EntityGetSelectedClassnamesWalker : public scene::Graph::Walker
-{
-  Classnames& m_classnames;
+class EntityGetSelectedPropertyValuesWalker : public scene::Graph::Walker {
+    PropertyValues &m_propertyvalues;
+    const char *m_prop;
 public:
-  EntityGetSelectedClassnamesWalker(Classnames& classnames)
-    : m_classnames(classnames)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    Selectable* selectable = Instance_getSelectable(instance);
-    if(selectable != 0
-      && selectable->isSelected())
+    EntityGetSelectedPropertyValuesWalker(const char *prop, PropertyValues &propertyvalues)
+            : m_propertyvalues(propertyvalues), m_prop(prop)
+    {
+    }
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
     {
-      Entity* entity = Node_getEntity(path.top());
-      if(entity != 0)
-      {
-        m_classnames.push_back(entity->getKeyValue("classname"));
-      }
+        Selectable *selectable = Instance_getSelectable(instance);
+        if (selectable != 0
+            && selectable->isSelected()) {
+            Entity *entity = Node_getEntity(path.top());
+            if (entity != 0) {
+                if (!propertyvalues_contain(m_propertyvalues, entity->getKeyValue(m_prop))) {
+                    m_propertyvalues.push_back(entity->getKeyValue(m_prop));
+                }
+            }
+        }
+        return true;
     }
-    return true;
-  }
 };
 
-void Scene_EntityGetClassnames(scene::Graph& graph, Classnames& classnames)
+void Scene_EntityGetPropertyValues(scene::Graph &graph, const char *prop, PropertyValues &propertyvalues)
 {
-  graph.traverse(EntityGetSelectedClassnamesWalker(classnames));
+    graph.traverse(EntityGetSelectedPropertyValuesWalker(prop, propertyvalues));
 }
 
 void Select_AllOfType()
 {
-  if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent)
-  {
-    if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace)
-    {
-      GlobalSelectionSystem().setSelectedAllComponents(false);
-      Scene_BrushSelectByShader_Component(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
-    }
-  }
-  else
-  {
-    Classnames classnames;
-    Scene_EntityGetClassnames(GlobalSceneGraph(), classnames);
-    GlobalSelectionSystem().setSelectedAll(false);
-    if(!classnames.empty())
-    {
-      Scene_EntitySelectByClassnames(GlobalSceneGraph(), classnames);
-    }
-    else
-    {
-      Scene_BrushSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
-      Scene_PatchSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
+    if (GlobalSelectionSystem().Mode() == SelectionSystem::eComponent) {
+        if (GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace) {
+            GlobalSelectionSystem().setSelectedAllComponents(false);
+            Scene_BrushSelectByShader_Component(GlobalSceneGraph(),
+                                                TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
+        }
+    } else {
+        PropertyValues propertyvalues;
+        const char *prop = EntityInspector_getCurrentKey();
+        if (!prop || !*prop) {
+            prop = "classname";
+        }
+        Scene_EntityGetPropertyValues(GlobalSceneGraph(), prop, propertyvalues);
+        GlobalSelectionSystem().setSelectedAll(false);
+        if (!propertyvalues.empty()) {
+            Scene_EntitySelectByPropertyValues(GlobalSceneGraph(), prop, propertyvalues);
+        } else {
+            Scene_BrushSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
+            Scene_PatchSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
+        }
     }
-  }
 }
 
 void Select_Inside(void)
 {
-       SelectByBounds<SelectionPolicy_Inside>::DoSelection();
+    SelectByBounds<SelectionPolicy_Inside>::DoSelection();
 }
 
 void Select_Touching(void)
 {
-       SelectByBounds<SelectionPolicy_Touching>::DoSelection(false);
+    SelectByBounds<SelectionPolicy_Touching>::DoSelection(false);
 }
 
 void Select_FitTexture(float horizontal, float vertical)
 {
-  if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
-  {
-    Scene_BrushFitTexture_Selected(GlobalSceneGraph(), horizontal, vertical);
-  }
-  Scene_BrushFitTexture_Component_Selected(GlobalSceneGraph(), horizontal, vertical);
+    if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
+        Scene_BrushFitTexture_Selected(GlobalSceneGraph(), horizontal, vertical);
+    }
+    Scene_BrushFitTexture_Component_Selected(GlobalSceneGraph(), horizontal, vertical);
 
-  SceneChangeNotify();
+    SceneChangeNotify();
 }
 
-inline void hide_node(scene::Nodenode, bool hide)
+inline void hide_node(scene::Node &node, bool hide)
 {
-  hide
+    hide
     ? node.enable(scene::Node::eHidden)
     : node.disable(scene::Node::eHidden);
 }
 
-class HideSelectedWalker : public scene::Graph::Walker
-{
-  bool m_hide;
+class HideSelectedWalker : public scene::Graph::Walker {
+    bool m_hide;
 public:
-  HideSelectedWalker(bool hide)
-    : m_hide(hide)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    Selectable* selectable = Instance_getSelectable(instance);
-    if(selectable != 0
-      && selectable->isSelected())
+    HideSelectedWalker(bool hide)
+            : m_hide(hide)
+    {
+    }
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
     {
-      hide_node(path.top(), m_hide);
+        Selectable *selectable = Instance_getSelectable(instance);
+        if (selectable != 0
+            && selectable->isSelected()) {
+            hide_node(path.top(), m_hide);
+        }
+        return true;
     }
-    return true;
-  }
 };
 
 void Scene_Hide_Selected(bool hide)
 {
-  GlobalSceneGraph().traverse(HideSelectedWalker(hide));
+    GlobalSceneGraph().traverse(HideSelectedWalker(hide));
 }
 
 void Select_Hide()
 {
-  Scene_Hide_Selected(true);
-  SceneChangeNotify();
+    Scene_Hide_Selected(true);
+    SceneChangeNotify();
 }
 
 void HideSelected()
 {
-  Select_Hide();
-  GlobalSelectionSystem().setSelectedAll(false);
+    Select_Hide();
+    GlobalSelectionSystem().setSelectedAll(false);
 }
 
 
-class HideAllWalker : public scene::Graph::Walker
-{
-  bool m_hide;
+class HideAllWalker : public scene::Graph::Walker {
+    bool m_hide;
 public:
-  HideAllWalker(bool hide)
-    : m_hide(hide)
-  {
-  }
-  bool pre(const scene::Path& path, scene::Instance& instance) const
-  {
-    hide_node(path.top(), m_hide);
-    return true;
-  }
+    HideAllWalker(bool hide)
+            : m_hide(hide)
+    {
+    }
+
+    bool pre(const scene::Path &path, scene::Instance &instance) const
+    {
+        hide_node(path.top(), m_hide);
+        return true;
+    }
 };
 
 void Scene_Hide_All(bool hide)
 {
-  GlobalSceneGraph().traverse(HideAllWalker(hide));
+    GlobalSceneGraph().traverse(HideAllWalker(hide));
 }
 
 void Select_ShowAllHidden()
 {
-  Scene_Hide_All(false);
-  SceneChangeNotify();
+    Scene_Hide_All(false);
+    SceneChangeNotify();
 }
 
 
-
 void Selection_Flipx()
 {
-  UndoableCommand undo("mirrorSelected -axis x");
-  Select_FlipAxis(0);
+    UndoableCommand undo("mirrorSelected -axis x");
+    Select_FlipAxis(0);
 }
 
 void Selection_Flipy()
 {
-  UndoableCommand undo("mirrorSelected -axis y");
-  Select_FlipAxis(1);
+    UndoableCommand undo("mirrorSelected -axis y");
+    Select_FlipAxis(1);
 }
 
 void Selection_Flipz()
 {
-  UndoableCommand undo("mirrorSelected -axis z");
-  Select_FlipAxis(2);
+    UndoableCommand undo("mirrorSelected -axis z");
+    Select_FlipAxis(2);
 }
 
 void Selection_Rotatex()
 {
-  UndoableCommand undo("rotateSelected -axis x -angle -90");
-  Select_RotateAxis(0,-90);
+    UndoableCommand undo("rotateSelected -axis x -angle -90");
+    Select_RotateAxis(0, -90);
 }
 
 void Selection_Rotatey()
 {
-  UndoableCommand undo("rotateSelected -axis y -angle 90");
-  Select_RotateAxis(1, 90);
+    UndoableCommand undo("rotateSelected -axis y -angle 90");
+    Select_RotateAxis(1, 90);
 }
 
 void Selection_Rotatez()
 {
-  UndoableCommand undo("rotateSelected -axis z -angle -90");
-  Select_RotateAxis(2,-90);
+    UndoableCommand undo("rotateSelected -axis z -angle -90");
+    Select_RotateAxis(2, -90);
 }
 
 
-
 void Nudge(int nDim, float fNudge)
 {
-  Vector3 translate(0, 0, 0);
-  translate[nDim] = fNudge;
-  
-  GlobalSelectionSystem().translateSelected(translate);
+    Vector3 translate(0, 0, 0);
+    translate[nDim] = fNudge;
+
+    GlobalSelectionSystem().translateSelected(translate);
 }
 
 void Selection_NudgeZ(float amount)
 {
-  StringOutputStream command;
-  command << "nudgeSelected -axis z -amount " << amount;
-  UndoableCommand undo(command.c_str());
+    StringOutputStream command;
+    command << "nudgeSelected -axis z -amount " << amount;
+    UndoableCommand undo(command.c_str());
 
-  Nudge(2, amount);
+    Nudge(2, amount);
 }
 
 void Selection_MoveDown()
 {
-  Selection_NudgeZ(-GetGridSize());
+    Selection_NudgeZ(-GetGridSize());
 }
 
 void Selection_MoveUp()
 {
-  Selection_NudgeZ(GetGridSize());
+    Selection_NudgeZ(GetGridSize());
 }
 
-void SceneSelectionChange(const Selectableselectable)
+void SceneSelectionChange(const Selectable &selectable)
 {
-  SceneChangeNotify();
+    SceneChangeNotify();
 }
 
 SignalHandlerId Selection_boundsChanged;
 
 void Selection_construct()
 {
-  typedef FreeCaller1<const Selectable&, SceneSelectionChange> SceneSelectionChangeCaller;
-  GlobalSelectionSystem().addSelectionChangeCallback(SceneSelectionChangeCaller());
-  typedef FreeCaller1<const Selectable&, UpdateWorkzone_ForSelectionChanged> UpdateWorkzoneForSelectionChangedCaller;
-  GlobalSelectionSystem().addSelectionChangeCallback(UpdateWorkzoneForSelectionChangedCaller());
-  typedef FreeCaller<UpdateWorkzone_ForSelection> UpdateWorkzoneForSelectionCaller;
-  Selection_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(UpdateWorkzoneForSelectionCaller());
+    typedef FreeCaller<void(const Selectable &), SceneSelectionChange> SceneSelectionChangeCaller;
+    GlobalSelectionSystem().addSelectionChangeCallback(SceneSelectionChangeCaller());
+    typedef FreeCaller<void(
+            const Selectable &), UpdateWorkzone_ForSelectionChanged> UpdateWorkzoneForSelectionChangedCaller;
+    GlobalSelectionSystem().addSelectionChangeCallback(UpdateWorkzoneForSelectionChangedCaller());
+    typedef FreeCaller<void(), UpdateWorkzone_ForSelection> UpdateWorkzoneForSelectionCaller;
+    Selection_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(UpdateWorkzoneForSelectionCaller());
 }
 
 void Selection_destroy()
 {
-  GlobalSceneGraph().removeBoundsChangedCallback(Selection_boundsChanged);
+    GlobalSceneGraph().removeBoundsChangedCallback(Selection_boundsChanged);
 }
 
 
 #include "gtkdlgs.h"
-#include <gtk/gtkbox.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtklabel.h>
 #include <gdk/gdkkeysyms.h>
 
 
-inline Quaternion quaternion_for_euler_xyz_degrees(const Vector3eulerXYZ)
+inline Quaternion quaternion_for_euler_xyz_degrees(const Vector3 &eulerXYZ)
 {
 #if 0
-  return quaternion_for_matrix4_rotation(matrix4_rotation_for_euler_xyz_degrees(eulerXYZ));
+    return quaternion_for_matrix4_rotation( matrix4_rotation_for_euler_xyz_degrees( eulerXYZ ) );
 #elif 0
-  return quaternion_multiplied_by_quaternion(
-    quaternion_multiplied_by_quaternion(
-      quaternion_for_z(degrees_to_radians(eulerXYZ[2])),
-      quaternion_for_y(degrees_to_radians(eulerXYZ[1]))
-    ),
-    quaternion_for_x(degrees_to_radians(eulerXYZ[0]))
-  );
+    return quaternion_multiplied_by_quaternion(
+               quaternion_multiplied_by_quaternion(
+                   quaternion_for_z( degrees_to_radians( eulerXYZ[2] ) ),
+                   quaternion_for_y( degrees_to_radians( eulerXYZ[1] ) )
+                   ),
+               quaternion_for_x( degrees_to_radians( eulerXYZ[0] ) )
+               );
 #elif 1
-  double cx = cos(degrees_to_radians(eulerXYZ[0] * 0.5));
-  double sx = sin(degrees_to_radians(eulerXYZ[0] * 0.5));
-  double cy = cos(degrees_to_radians(eulerXYZ[1] * 0.5));
-  double sy = sin(degrees_to_radians(eulerXYZ[1] * 0.5));
-  double cz = cos(degrees_to_radians(eulerXYZ[2] * 0.5));
-  double sz = sin(degrees_to_radians(eulerXYZ[2] * 0.5));
-
-  return Quaternion(
-    cz * cy * sx - sz * sy * cx,
-    cz * sy * cx + sz * cy * sx,
-    sz * cy * cx - cz * sy * sx,
-    cz * cy * cx + sz * sy * sx
-  );
+    double cx = cos(degrees_to_radians(eulerXYZ[0] * 0.5));
+    double sx = sin(degrees_to_radians(eulerXYZ[0] * 0.5));
+    double cy = cos(degrees_to_radians(eulerXYZ[1] * 0.5));
+    double sy = sin(degrees_to_radians(eulerXYZ[1] * 0.5));
+    double cz = cos(degrees_to_radians(eulerXYZ[2] * 0.5));
+    double sz = sin(degrees_to_radians(eulerXYZ[2] * 0.5));
+
+    return Quaternion(
+            cz * cy * sx - sz * sy * cx,
+            cz * sy * cx + sz * cy * sx,
+            sz * cy * cx - cz * sy * sx,
+            cz * cy * cx + sz * sy * sx
+    );
 #endif
 }
 
-struct RotateDialog
-{
-  GtkSpinButton* x;
-  GtkSpinButton* y;
-  GtkSpinButton* z;
+struct RotateDialog {
+    ui::SpinButton x{ui::null};
+    ui::SpinButton y{ui::null};
+    ui::SpinButton z{ui::null};
+    ui::Window window{ui::null};
 };
 
-static void rotatedlg_apply (GtkWidget *widget, RotateDialog* rotateDialog)
+static gboolean rotatedlg_apply(ui::Widget widget, RotateDialog *rotateDialog)
 {
-  Vector3 eulerXYZ;
-
-  eulerXYZ[0] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->x));
-  gtk_spin_button_set_value(rotateDialog->x, 0.0f); // reset to 0 on Apply
-  
-  eulerXYZ[1] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->y));
-  gtk_spin_button_set_value(rotateDialog->y, 0.0f);
-  
-  eulerXYZ[2] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->z));
-  gtk_spin_button_set_value(rotateDialog->z, 0.0f);
-
-  StringOutputStream command;
-  command << "rotateSelectedEulerXYZ -x " << eulerXYZ[0] << " -y " << eulerXYZ[1] << " -z " << eulerXYZ[2];
-  UndoableCommand undo(command.c_str());
-
-  GlobalSelectionSystem().rotateSelected(quaternion_for_euler_xyz_degrees(eulerXYZ));
+    Vector3 eulerXYZ;
+
+    eulerXYZ[0] = static_cast<float>( gtk_spin_button_get_value(rotateDialog->x));
+    eulerXYZ[1] = static_cast<float>( gtk_spin_button_get_value(rotateDialog->y));
+    eulerXYZ[2] = static_cast<float>( gtk_spin_button_get_value(rotateDialog->z));
+
+    StringOutputStream command;
+    command << "rotateSelectedEulerXYZ -x " << eulerXYZ[0] << " -y " << eulerXYZ[1] << " -z " << eulerXYZ[2];
+    UndoableCommand undo(command.c_str());
+
+    GlobalSelectionSystem().rotateSelected(quaternion_for_euler_xyz_degrees(eulerXYZ));
+    return TRUE;
 }
 
-void DoRotateDlg()
+static gboolean rotatedlg_cancel(ui::Widget widget, RotateDialog *rotateDialog)
 {
-  ModalDialog dialog;
-  RotateDialog rotateDialog;
+    rotateDialog->window.hide();
 
-  GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Arbitrary rotation", G_CALLBACK(dialog_delete_callback), &dialog);
+    gtk_spin_button_set_value(rotateDialog->x, 0.0f); // reset to 0 on close
+    gtk_spin_button_set_value(rotateDialog->y, 0.0f);
+    gtk_spin_button_set_value(rotateDialog->z, 0.0f);
 
-  GtkAccelGroup* accel = gtk_accel_group_new();
-  gtk_window_add_accel_group(window, accel);
+    return TRUE;
+}
 
-  {
-    GtkHBox* hbox = create_dialog_hbox(4, 4);
-    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
-    {
-      GtkTable* table = create_dialog_table(3, 2, 4, 4);
-      gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
-      {
-        GtkWidget* label = gtk_label_new ("  X  ");
-        gtk_widget_show (label);
-        gtk_table_attach(table, label, 0, 1, 0, 1,
-                          (GtkAttachOptions) (0),
-                          (GtkAttachOptions) (0), 0, 0);
-      }
-      {
-        GtkWidget* label = gtk_label_new ("  Y  ");
-        gtk_widget_show (label);
-        gtk_table_attach(table, label, 0, 1, 1, 2,
-                          (GtkAttachOptions) (0),
-                          (GtkAttachOptions) (0), 0, 0);
-      }
-      {
-        GtkWidget* label = gtk_label_new ("  Z  ");
-        gtk_widget_show (label);
-        gtk_table_attach(table, label, 0, 1, 2, 3,
-                          (GtkAttachOptions) (0),
-                          (GtkAttachOptions) (0), 0, 0);
-      }
-      {
-        GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
-        GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
-        gtk_widget_show(GTK_WIDGET(spin));
-        gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 0, 1,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
-        gtk_spin_button_set_wrap(spin, TRUE);
-
-        gtk_widget_grab_focus(GTK_WIDGET(spin));
-
-        rotateDialog.x = spin;
-      }
-      {
-        GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
-        GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
-        gtk_widget_show(GTK_WIDGET(spin));
-        gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 1, 2,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
-        gtk_spin_button_set_wrap(spin, TRUE);
-
-        rotateDialog.y = spin;
-      }
-      {
-        GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
-        GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
-        gtk_widget_show(GTK_WIDGET(spin));
-        gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 2, 3,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
-        gtk_spin_button_set_wrap(spin, TRUE);
-
-        rotateDialog.z = spin;
-      }
-    }
-    {
-      GtkVBox* vbox = create_dialog_vbox(4);
-      gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
-      {
-        GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
-        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-        widget_make_default(GTK_WIDGET(button));
-        gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
-        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-        gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Apply", G_CALLBACK(rotatedlg_apply), &rotateDialog);
-        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
+static gboolean rotatedlg_ok(ui::Widget widget, RotateDialog *rotateDialog)
+{
+    rotatedlg_apply(widget, rotateDialog);
+    rotateDialog->window.hide();
+    return TRUE;
+}
+
+static gboolean rotatedlg_delete(ui::Widget widget, GdkEventAny *event, RotateDialog *rotateDialog)
+{
+    rotatedlg_cancel(widget, rotateDialog);
+    return TRUE;
+}
+
+RotateDialog g_rotate_dialog;
+
+void DoRotateDlg()
+{
+    if (!g_rotate_dialog.window) {
+        g_rotate_dialog.window = MainFrame_getWindow().create_dialog_window("Arbitrary rotation",
+                                                                            G_CALLBACK(rotatedlg_delete),
+                                                                            &g_rotate_dialog);
+
+        auto accel = ui::AccelGroup(ui::New);
+        g_rotate_dialog.window.add_accel_group(accel);
+
+        {
+            auto hbox = create_dialog_hbox(4, 4);
+            g_rotate_dialog.window.add(hbox);
+            {
+                auto table = create_dialog_table(3, 2, 4, 4);
+                hbox.pack_start(table, TRUE, TRUE, 0);
+                {
+                    ui::Widget label = ui::Label("  X  ");
+                    label.show();
+                    table.attach(label, {0, 1, 0, 1}, {0, 0});
+                }
+                {
+                    ui::Widget label = ui::Label("  Y  ");
+                    label.show();
+                    table.attach(label, {0, 1, 1, 2}, {0, 0});
+                }
+                {
+                    ui::Widget label = ui::Label("  Z  ");
+                    label.show();
+                    table.attach(label, {0, 1, 2, 3}, {0, 0});
+                }
+                {
+                    auto adj = ui::Adjustment(0, -359, 359, 1, 10, 0);
+                    auto spin = ui::SpinButton(adj, 1, 0);
+                    spin.show();
+                    table.attach(spin, {1, 2, 0, 1}, {GTK_EXPAND | GTK_FILL, 0});
+                    spin.dimensions(64, -1);
+                    gtk_spin_button_set_wrap(spin, TRUE);
+
+                    gtk_widget_grab_focus(spin);
+
+                    g_rotate_dialog.x = spin;
+                }
+                {
+                    auto adj = ui::Adjustment(0, -359, 359, 1, 10, 0);
+                    auto spin = ui::SpinButton(adj, 1, 0);
+                    spin.show();
+                    table.attach(spin, {1, 2, 1, 2}, {GTK_EXPAND | GTK_FILL, 0});
+                    spin.dimensions(64, -1);
+                    gtk_spin_button_set_wrap(spin, TRUE);
+
+                    g_rotate_dialog.y = spin;
+                }
+                {
+                    auto adj = ui::Adjustment(0, -359, 359, 1, 10, 0);
+                    auto spin = ui::SpinButton(adj, 1, 0);
+                    spin.show();
+                    table.attach(spin, {1, 2, 2, 3}, {GTK_EXPAND | GTK_FILL, 0});
+                    spin.dimensions(64, -1);
+                    gtk_spin_button_set_wrap(spin, TRUE);
+
+                    g_rotate_dialog.z = spin;
+                }
+            }
+            {
+                auto vbox = create_dialog_vbox(4);
+                hbox.pack_start(vbox, TRUE, TRUE, 0);
+                {
+                    auto button = create_dialog_button("OK", G_CALLBACK(rotatedlg_ok), &g_rotate_dialog);
+                    vbox.pack_start(button, FALSE, FALSE, 0);
+                    widget_make_default(button);
+                    gtk_widget_add_accelerator(button, "clicked", accel, GDK_KEY_Return, (GdkModifierType) 0,
+                                               (GtkAccelFlags) 0);
+                }
+                {
+                    auto button = create_dialog_button("Cancel", G_CALLBACK(rotatedlg_cancel), &g_rotate_dialog);
+                    vbox.pack_start(button, FALSE, FALSE, 0);
+                    gtk_widget_add_accelerator(button, "clicked", accel, GDK_KEY_Escape, (GdkModifierType) 0,
+                                               (GtkAccelFlags) 0);
+                }
+                {
+                    auto button = create_dialog_button("Apply", G_CALLBACK(rotatedlg_apply), &g_rotate_dialog);
+                    vbox.pack_start(button, FALSE, FALSE, 0);
+                }
+            }
+        }
     }
-  }
 
-  if(modal_dialog_show(window, dialog) == eIDOK)
-  {
-    rotatedlg_apply(0, &rotateDialog);
-  }
+    g_rotate_dialog.window.show();
+}
+
+
+struct ScaleDialog {
+    ui::Entry x{ui::null};
+    ui::Entry y{ui::null};
+    ui::Entry z{ui::null};
+    ui::Window window{ui::null};
+};
+
+static gboolean scaledlg_apply(ui::Widget widget, ScaleDialog *scaleDialog)
+{
+    float sx, sy, sz;
+
+    sx = static_cast<float>( atof(gtk_entry_get_text(GTK_ENTRY(scaleDialog->x))));
+    sy = static_cast<float>( atof(gtk_entry_get_text(GTK_ENTRY(scaleDialog->y))));
+    sz = static_cast<float>( atof(gtk_entry_get_text(GTK_ENTRY(scaleDialog->z))));
 
-  gtk_widget_destroy(GTK_WIDGET(window));
+    StringOutputStream command;
+    command << "scaleSelected -x " << sx << " -y " << sy << " -z " << sz;
+    UndoableCommand undo(command.c_str());
+
+    Select_Scale(sx, sy, sz);
+
+    return TRUE;
 }
 
-void DoScaleDlg()
+static gboolean scaledlg_cancel(ui::Widget widget, ScaleDialog *scaleDialog)
 {
-  ModalDialog dialog;
-  GtkWidget* x;
-  GtkWidget* y;
-  GtkWidget* z;
+    scaleDialog->window.hide();
 
-  GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Scale", G_CALLBACK(dialog_delete_callback), &dialog);
+    scaleDialog->x.text("1.0");
+    scaleDialog->y.text("1.0");
+    scaleDialog->z.text("1.0");
 
-  GtkAccelGroup* accel = gtk_accel_group_new();
-  gtk_window_add_accel_group(window, accel);
+    return TRUE;
+}
 
-  {
-    GtkHBox* hbox = create_dialog_hbox(4, 4);
-    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
-    {
-      GtkTable* table = create_dialog_table(3, 2, 4, 4);
-      gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
-      {
-        GtkWidget* label = gtk_label_new ("X:");
-        gtk_widget_show (label);
-        gtk_table_attach(table, label, 0, 1, 0, 1,
-                          (GtkAttachOptions) (GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-      }
-      {
-        GtkWidget* label = gtk_label_new ("Y:");
-        gtk_widget_show (label);
-        gtk_table_attach(table, label, 0, 1, 1, 2,
-                          (GtkAttachOptions) (GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-      }
-      {
-        GtkWidget* label = gtk_label_new ("Z:");
-        gtk_widget_show (label);
-        gtk_table_attach(table, label, 0, 1, 2, 3,
-                          (GtkAttachOptions) (GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-      }
-      {
-        GtkWidget* entry = gtk_entry_new();
-        gtk_widget_show (entry);
-        gtk_table_attach(table, entry, 1, 2, 0, 1,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-
-        gtk_widget_grab_focus(entry);
-
-        x = entry;
-      }
-      {
-        GtkWidget* entry = gtk_entry_new();
-        gtk_widget_show (entry);
-        gtk_table_attach(table, entry, 1, 2, 1, 2,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-
-        y = entry;
-      }
-      {
-        GtkWidget* entry = gtk_entry_new();
-        gtk_widget_show (entry);
-        gtk_table_attach(table, entry, 1, 2, 2, 3,
-                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                          (GtkAttachOptions) (0), 0, 0);
-
-        z = entry;
-      }
-    }
-    {
-      GtkVBox* vbox = create_dialog_vbox(4);
-      gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
-      {
-        GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
-        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-        widget_make_default(GTK_WIDGET(button));
-        gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
-        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-        gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
-      }
-    }
-  }
+static gboolean scaledlg_ok(ui::Widget widget, ScaleDialog *scaleDialog)
+{
+    scaledlg_apply(widget, scaleDialog);
+    scaleDialog->window.hide();
+    return TRUE;
+}
 
-  // Initialize dialog
-  gtk_entry_set_text (GTK_ENTRY (x), "1.0");
-  gtk_entry_set_text (GTK_ENTRY (y), "1.0");
-  gtk_entry_set_text (GTK_ENTRY (z), "1.0");
+static gboolean scaledlg_delete(ui::Widget widget, GdkEventAny *event, ScaleDialog *scaleDialog)
+{
+    scaledlg_cancel(widget, scaleDialog);
+    return TRUE;
+}
 
-  if(modal_dialog_show(window, dialog) == eIDOK)
-  {
-    float sx, sy, sz;
-    sx = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (x))));
-    sy = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (y))));
-    sz = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (z))));
+ScaleDialog g_scale_dialog;
 
-    if (sx > 0 && sy > 0 && sz > 0)
-    {
-      StringOutputStream command;
-      command << "scaleSelected -x " << sx << " -y " << sy << " -z " << sz;
-      UndoableCommand undo(command.c_str());
+void DoScaleDlg()
+{
+    if (!g_scale_dialog.window) {
+        g_scale_dialog.window = MainFrame_getWindow().create_dialog_window("Arbitrary scale",
+                                                                           G_CALLBACK(scaledlg_delete),
+                                                                           &g_scale_dialog);
 
-      Select_Scale(sx, sy, sz);
-    }
-    else
-    {
-      globalOutputStream() << "Warning.. Tried to scale by a zero value.";
+        auto accel = ui::AccelGroup(ui::New);
+        g_scale_dialog.window.add_accel_group(accel);
+
+        {
+            auto hbox = create_dialog_hbox(4, 4);
+            g_scale_dialog.window.add(hbox);
+            {
+                auto table = create_dialog_table(3, 2, 4, 4);
+                hbox.pack_start(table, TRUE, TRUE, 0);
+                {
+                    ui::Widget label = ui::Label("  X  ");
+                    label.show();
+                    table.attach(label, {0, 1, 0, 1}, {0, 0});
+                }
+                {
+                    ui::Widget label = ui::Label("  Y  ");
+                    label.show();
+                    table.attach(label, {0, 1, 1, 2}, {0, 0});
+                }
+                {
+                    ui::Widget label = ui::Label("  Z  ");
+                    label.show();
+                    table.attach(label, {0, 1, 2, 3}, {0, 0});
+                }
+                {
+                    auto entry = ui::Entry(ui::New);
+                    entry.text("1.0");
+                    entry.show();
+                    table.attach(entry, {1, 2, 0, 1}, {GTK_EXPAND | GTK_FILL, 0});
+
+                    g_scale_dialog.x = entry;
+                }
+                {
+                    auto entry = ui::Entry(ui::New);
+                    entry.text("1.0");
+                    entry.show();
+                    table.attach(entry, {1, 2, 1, 2}, {GTK_EXPAND | GTK_FILL, 0});
+
+                    g_scale_dialog.y = entry;
+                }
+                {
+                    auto entry = ui::Entry(ui::New);
+                    entry.text("1.0");
+                    entry.show();
+                    table.attach(entry, {1, 2, 2, 3}, {GTK_EXPAND | GTK_FILL, 0});
+
+                    g_scale_dialog.z = entry;
+                }
+            }
+            {
+                auto vbox = create_dialog_vbox(4);
+                hbox.pack_start(vbox, TRUE, TRUE, 0);
+                {
+                    auto button = create_dialog_button("OK", G_CALLBACK(scaledlg_ok), &g_scale_dialog);
+                    vbox.pack_start(button, FALSE, FALSE, 0);
+                    widget_make_default(button);
+                    gtk_widget_add_accelerator(button, "clicked", accel, GDK_KEY_Return, (GdkModifierType) 0,
+                                               (GtkAccelFlags) 0);
+                }
+                {
+                    auto button = create_dialog_button("Cancel", G_CALLBACK(scaledlg_cancel), &g_scale_dialog);
+                    vbox.pack_start(button, FALSE, FALSE, 0);
+                    gtk_widget_add_accelerator(button, "clicked", accel, GDK_KEY_Escape, (GdkModifierType) 0,
+                                               (GtkAccelFlags) 0);
+                }
+                {
+                    auto button = create_dialog_button("Apply", G_CALLBACK(scaledlg_apply), &g_scale_dialog);
+                    vbox.pack_start(button, FALSE, FALSE, 0);
+                }
+            }
+        }
     }
-  }
 
-  gtk_widget_destroy(GTK_WIDGET(window));
+    g_scale_dialog.window.show();
 }