2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "debugging/debugging.h"
27 #include "iselection.h"
32 #include "stream/stringstream.h"
33 #include "signal/isignal.h"
34 #include "shaderlib.h"
37 #include "gtkutil/idledraw.h"
38 #include "gtkutil/dialog.h"
39 #include "gtkutil/widget.h"
40 #include "brushmanip.h"
42 #include "patchmanip.h"
43 #include "patchdialog.h"
44 #include "selection.h"
45 #include "texwindow.h"
47 #include "mainframe.h"
53 select_workzone_t g_select_workzone;
57 Loops over all selected brushes and stores their
58 world AABBs in the specified array.
60 class CollectSelectedBrushesBounds : public SelectionSystem::Visitor
62 AABB* m_bounds; // array of AABBs
63 Unsigned m_max; // max AABB-elements in array
64 Unsigned& m_count;// count of valid AABBs stored in array
67 CollectSelectedBrushesBounds(AABB* bounds, Unsigned max, Unsigned& count)
75 void visit(scene::Instance& instance) const
77 ASSERT_MESSAGE(m_count <= m_max, "Invalid m_count in CollectSelectedBrushesBounds");
79 // stop if the array is already full
83 Selectable* selectable = Instance_getSelectable(instance);
85 && instance.isSelected())
88 if(Instance_getBrush(instance) != 0)
90 m_bounds[m_count] = instance.worldAABB();
98 Selects all objects that intersect one of the bounding AABBs.
99 The exact intersection-method is specified through TSelectionPolicy
101 template<class TSelectionPolicy>
102 class SelectByBounds : public scene::Graph::Walker
104 AABB* m_aabbs; // selection aabbs
105 Unsigned m_count; // number of aabbs in m_aabbs
106 TSelectionPolicy policy; // type that contains a custom intersection method aabb<->aabb
109 SelectByBounds(AABB* aabbs, Unsigned count)
115 bool pre(const scene::Path& path, scene::Instance& instance) const
117 Selectable* selectable = Instance_getSelectable(instance);
120 Entity* entity = Node_getEntity(path.top());
123 if(string_equal(entity->getKeyValue("classname"), "worldspawn"))
127 if( (path.size() > 1) &&
128 (!path.top().get().isRoot()) &&
132 for(Unsigned i = 0; i < m_count; ++i)
134 if(policy.Evaluate(m_aabbs[i], instance))
136 selectable->setSelected(true);
145 Performs selection operation on the global scenegraph.
146 If delete_bounds_src is true, then the objects which were
147 used as source for the selection aabbs will be deleted.
149 static void DoSelection(bool delete_bounds_src = true)
151 if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
153 // we may not need all AABBs since not all selected objects have to be brushes
154 const Unsigned max = (Unsigned)GlobalSelectionSystem().countSelected();
155 AABB* aabbs = new AABB[max];
158 CollectSelectedBrushesBounds collector(aabbs, max, count);
159 GlobalSelectionSystem().foreachSelected(collector);
161 // nothing usable in selection
168 // delete selected objects
169 if(delete_bounds_src)// see deleteSelection
171 UndoableCommand undo("deleteSelected");
175 // select objects with bounds
176 GlobalSceneGraph().traverse(SelectByBounds<TSelectionPolicy>(aabbs, count));
185 SelectionPolicy for SelectByBounds
186 Returns true if box and the AABB of instance intersect
188 class SelectionPolicy_Touching
191 bool Evaluate(const AABB& box, scene::Instance& instance) const
193 const AABB& other(instance.worldAABB());
194 for(Unsigned i = 0; i < 3; ++i)
196 if(fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] + other.extents[i]))
204 SelectionPolicy for SelectByBounds
205 Returns true if the AABB of instance is inside box
207 class SelectionPolicy_Inside
210 bool Evaluate(const AABB& box, scene::Instance& instance) const
212 const AABB& other(instance.worldAABB());
213 for(Unsigned i = 0; i < 3; ++i)
215 if(fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] - other.extents[i]))
222 class DeleteSelected : public scene::Graph::Walker
224 mutable bool m_remove;
225 mutable bool m_removedChild;
228 : m_remove(false), m_removedChild(false)
231 bool pre(const scene::Path& path, scene::Instance& instance) const
233 m_removedChild = false;
235 Selectable* selectable = Instance_getSelectable(instance);
237 && selectable->isSelected()
239 && !path.top().get().isRoot())
243 return false;// dont traverse into child elements
247 void post(const scene::Path& path, scene::Instance& instance) const
252 m_removedChild = false;
254 // delete empty entities
255 Entity* entity = Node_getEntity(path.top());
257 && path.top().get_pointer() != Map_FindWorldspawn(g_map)
258 && Node_getTraversable(path.top())->empty())
260 Path_deleteTop(path);
264 // node should be removed
267 if(Node_isEntity(path.parent()) != 0)
269 m_removedChild = true;
273 Path_deleteTop(path);
278 void Scene_DeleteSelected(scene::Graph& graph)
280 graph.traverse(DeleteSelected());
284 void Select_Delete (void)
286 Scene_DeleteSelected(GlobalSceneGraph());
289 class InvertSelectionWalker : public scene::Graph::Walker
291 SelectionSystem::EMode m_mode;
292 mutable Selectable* m_selectable;
294 InvertSelectionWalker(SelectionSystem::EMode mode)
295 : m_mode(mode), m_selectable(0)
298 bool pre(const scene::Path& path, scene::Instance& instance) const
300 Selectable* selectable = Instance_getSelectable(instance);
305 case SelectionSystem::eEntity:
306 if(Node_isEntity(path.top()) != 0)
308 m_selectable = path.top().get().visible() ? selectable : 0;
311 case SelectionSystem::ePrimitive:
312 m_selectable = path.top().get().visible() ? selectable : 0;
314 case SelectionSystem::eComponent:
320 void post(const scene::Path& path, scene::Instance& instance) const
322 if(m_selectable != 0)
324 m_selectable->setSelected(!m_selectable->isSelected());
330 void Scene_Invert_Selection(scene::Graph& graph)
332 graph.traverse(InvertSelectionWalker(GlobalSelectionSystem().Mode()));
337 Scene_Invert_Selection(GlobalSceneGraph());
340 class ExpandSelectionToEntitiesWalker : public scene::Graph::Walker
342 mutable std::size_t m_depth;
343 NodeSmartReference worldspawn;
345 ExpandSelectionToEntitiesWalker() : m_depth(0), worldspawn(Map_FindOrInsertWorldspawn(g_map))
348 bool pre(const scene::Path& path, scene::Instance& instance) const
353 NodeSmartReference me(path.top().get());
357 if(m_depth == 2) // entity depth
359 // traverse and select children if any one is selected
360 if(instance.childSelected())
361 Instance_setSelected(instance, true);
362 return Node_getEntity(path.top())->isContainer() && instance.isSelected();
364 else if(m_depth == 3) // primitive depth
366 Instance_setSelected(instance, true);
371 void post(const scene::Path& path, scene::Instance& instance) const
377 void Scene_ExpandSelectionToEntities()
379 GlobalSceneGraph().traverse(ExpandSelectionToEntitiesWalker());
385 void Selection_UpdateWorkzone()
387 if(GlobalSelectionSystem().countSelected() != 0)
389 Select_GetBounds(g_select_workzone.d_work_min, g_select_workzone.d_work_max);
392 typedef FreeCaller<Selection_UpdateWorkzone> SelectionUpdateWorkzoneCaller;
394 IdleDraw g_idleWorkzone = IdleDraw(SelectionUpdateWorkzoneCaller());
397 const select_workzone_t& Select_getWorkZone()
399 g_idleWorkzone.flush();
400 return g_select_workzone;
403 void UpdateWorkzone_ForSelection()
405 g_idleWorkzone.queueDraw();
408 // update the workzone to the current selection
409 void UpdateWorkzone_ForSelectionChanged(const Selectable& selectable)
411 if(selectable.isSelected())
413 UpdateWorkzone_ForSelection();
417 void Select_SetShader(const char* shader)
419 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
421 Scene_BrushSetShader_Selected(GlobalSceneGraph(), shader);
422 Scene_PatchSetShader_Selected(GlobalSceneGraph(), shader);
424 Scene_BrushSetShader_Component_Selected(GlobalSceneGraph(), shader);
427 void Select_SetTexdef(const TextureProjection& projection)
429 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
431 Scene_BrushSetTexdef_Selected(GlobalSceneGraph(), projection);
433 Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection);
436 void Select_SetFlags(const ContentsFlagsValue& flags)
438 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
440 Scene_BrushSetFlags_Selected(GlobalSceneGraph(), flags);
442 Scene_BrushSetFlags_Component_Selected(GlobalSceneGraph(), flags);
445 void Select_GetBounds (Vector3& mins, Vector3& maxs)
448 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
449 maxs = vector3_added(bounds.origin, bounds.extents);
450 mins = vector3_subtracted(bounds.origin, bounds.extents);
453 void Select_GetMid (Vector3& mid)
456 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
457 mid = vector3_snapped(bounds.origin);
461 void Select_FlipAxis (int axis)
463 Vector3 flip(1, 1, 1);
465 GlobalSelectionSystem().scaleSelected(flip);
469 void Select_Scale(float x, float y, float z)
471 GlobalSelectionSystem().scaleSelected(Vector3(x, y, z));
487 inline Matrix4 matrix4_rotation_for_axis90(axis_t axis, sign_t sign)
492 if(sign == eSignPositive)
494 return matrix4_rotation_for_sincos_x(1, 0);
498 return matrix4_rotation_for_sincos_x(-1, 0);
501 if(sign == eSignPositive)
503 return matrix4_rotation_for_sincos_y(1, 0);
507 return matrix4_rotation_for_sincos_y(-1, 0);
509 default://case eAxisZ:
510 if(sign == eSignPositive)
512 return matrix4_rotation_for_sincos_z(1, 0);
516 return matrix4_rotation_for_sincos_z(-1, 0);
521 inline void matrix4_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign)
523 matrix4_multiply_by_matrix4(matrix, matrix4_rotation_for_axis90(axis, sign));
526 inline void matrix4_pivoted_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign, const Vector3& pivotpoint)
528 matrix4_translate_by_vec3(matrix, pivotpoint);
529 matrix4_rotate_by_axis90(matrix, axis, sign);
530 matrix4_translate_by_vec3(matrix, vector3_negated(pivotpoint));
533 inline Quaternion quaternion_for_axis90(axis_t axis, sign_t sign)
539 if(sign == eSignPositive)
541 return Quaternion(c_half_sqrt2f, 0, 0, c_half_sqrt2f);
545 return Quaternion(-c_half_sqrt2f, 0, 0, -c_half_sqrt2f);
548 if(sign == eSignPositive)
550 return Quaternion(0, c_half_sqrt2f, 0, c_half_sqrt2f);
554 return Quaternion(0, -c_half_sqrt2f, 0, -c_half_sqrt2f);
556 default://case eAxisZ:
557 if(sign == eSignPositive)
559 return Quaternion(0, 0, c_half_sqrt2f, c_half_sqrt2f);
563 return Quaternion(0, 0, -c_half_sqrt2f, -c_half_sqrt2f);
567 quaternion_for_matrix4_rotation(matrix4_rotation_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
571 void Select_RotateAxis (int axis, float deg)
573 if(fabs(deg) == 90.f)
575 GlobalSelectionSystem().rotateSelected(quaternion_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
582 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_x_degrees(deg)));
585 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_y_degrees(deg)));
588 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_z_degrees(deg)));
595 void Select_ShiftTexture(float x, float y)
597 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
599 Scene_BrushShiftTexdef_Selected(GlobalSceneGraph(), x, y);
600 Scene_PatchTranslateTexture_Selected(GlobalSceneGraph(), x, y);
602 //globalOutputStream() << "shift selected face textures: s=" << x << " t=" << y << '\n';
603 Scene_BrushShiftTexdef_Component_Selected(GlobalSceneGraph(), x, y);
606 void Select_ScaleTexture(float x, float y)
608 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
610 Scene_BrushScaleTexdef_Selected(GlobalSceneGraph(), x, y);
611 Scene_PatchScaleTexture_Selected(GlobalSceneGraph(), x, y);
613 Scene_BrushScaleTexdef_Component_Selected(GlobalSceneGraph(), x, y);
616 void Select_RotateTexture(float amt)
618 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
620 Scene_BrushRotateTexdef_Selected(GlobalSceneGraph(), amt);
621 Scene_PatchRotateTexture_Selected(GlobalSceneGraph(), amt);
623 Scene_BrushRotateTexdef_Component_Selected(GlobalSceneGraph(), amt);
626 // TTimo modified to handle shader architecture:
627 // expects shader names at input, comparison relies on shader names .. texture names no longer relevant
628 void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected)
630 if(!texdef_name_valid(pFind))
632 globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pFind << "', aborted\n";
635 if(!texdef_name_valid(pReplace))
637 globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pReplace << "', aborted\n";
641 StringOutputStream command;
642 command << "textureFindReplace -find " << pFind << " -replace " << pReplace;
643 UndoableCommand undo(command.c_str());
647 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
649 Scene_BrushFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
650 Scene_PatchFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
652 Scene_BrushFindReplaceShader_Component_Selected(GlobalSceneGraph(), pFind, pReplace);
656 Scene_BrushFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
657 Scene_PatchFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
661 typedef std::vector<const char*> Classnames;
663 bool classnames_match_entity(const Classnames& classnames, Entity* entity)
665 for(Classnames::const_iterator i = classnames.begin(); i != classnames.end(); ++i)
667 if(string_equal(entity->getKeyValue("classname"), *i))
675 class EntityFindByClassnameWalker : public scene::Graph::Walker
677 const Classnames& m_classnames;
679 EntityFindByClassnameWalker(const Classnames& classnames)
680 : m_classnames(classnames)
683 bool pre(const scene::Path& path, scene::Instance& instance) const
685 Entity* entity = Node_getEntity(path.top());
687 && classnames_match_entity(m_classnames, entity))
689 Instance_getSelectable(instance)->setSelected(true);
695 void Scene_EntitySelectByClassnames(scene::Graph& graph, const Classnames& classnames)
697 graph.traverse(EntityFindByClassnameWalker(classnames));
700 class EntityGetSelectedClassnamesWalker : public scene::Graph::Walker
702 Classnames& m_classnames;
704 EntityGetSelectedClassnamesWalker(Classnames& classnames)
705 : m_classnames(classnames)
708 bool pre(const scene::Path& path, scene::Instance& instance) const
710 Selectable* selectable = Instance_getSelectable(instance);
712 && selectable->isSelected())
714 Entity* entity = Node_getEntity(path.top());
717 m_classnames.push_back(entity->getKeyValue("classname"));
724 void Scene_EntityGetClassnames(scene::Graph& graph, Classnames& classnames)
726 graph.traverse(EntityGetSelectedClassnamesWalker(classnames));
729 void Select_AllOfType()
731 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent)
733 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace)
735 GlobalSelectionSystem().setSelectedAllComponents(false);
736 Scene_BrushSelectByShader_Component(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
741 Classnames classnames;
742 Scene_EntityGetClassnames(GlobalSceneGraph(), classnames);
743 GlobalSelectionSystem().setSelectedAll(false);
744 if(!classnames.empty())
746 Scene_EntitySelectByClassnames(GlobalSceneGraph(), classnames);
750 Scene_BrushSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
751 Scene_PatchSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
756 void Select_Inside(void)
758 SelectByBounds<SelectionPolicy_Inside>::DoSelection();
761 void Select_Touching(void)
763 SelectByBounds<SelectionPolicy_Touching>::DoSelection(false);
766 void Select_FitTexture(float horizontal, float vertical)
768 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
770 Scene_BrushFitTexture_Selected(GlobalSceneGraph(), horizontal, vertical);
772 Scene_BrushFitTexture_Component_Selected(GlobalSceneGraph(), horizontal, vertical);
777 inline void hide_node(scene::Node& node, bool hide)
780 ? node.enable(scene::Node::eHidden)
781 : node.disable(scene::Node::eHidden);
784 class HideSelectedWalker : public scene::Graph::Walker
788 HideSelectedWalker(bool hide)
792 bool pre(const scene::Path& path, scene::Instance& instance) const
794 Selectable* selectable = Instance_getSelectable(instance);
796 && selectable->isSelected())
798 hide_node(path.top(), m_hide);
804 void Scene_Hide_Selected(bool hide)
806 GlobalSceneGraph().traverse(HideSelectedWalker(hide));
811 Scene_Hide_Selected(true);
818 GlobalSelectionSystem().setSelectedAll(false);
822 class HideAllWalker : public scene::Graph::Walker
826 HideAllWalker(bool hide)
830 bool pre(const scene::Path& path, scene::Instance& instance) const
832 hide_node(path.top(), m_hide);
837 void Scene_Hide_All(bool hide)
839 GlobalSceneGraph().traverse(HideAllWalker(hide));
842 void Select_ShowAllHidden()
844 Scene_Hide_All(false);
850 void Selection_Flipx()
852 UndoableCommand undo("mirrorSelected -axis x");
856 void Selection_Flipy()
858 UndoableCommand undo("mirrorSelected -axis y");
862 void Selection_Flipz()
864 UndoableCommand undo("mirrorSelected -axis z");
868 void Selection_Rotatex()
870 UndoableCommand undo("rotateSelected -axis x -angle -90");
871 Select_RotateAxis(0,-90);
874 void Selection_Rotatey()
876 UndoableCommand undo("rotateSelected -axis y -angle 90");
877 Select_RotateAxis(1, 90);
880 void Selection_Rotatez()
882 UndoableCommand undo("rotateSelected -axis z -angle -90");
883 Select_RotateAxis(2,-90);
888 void Nudge(int nDim, float fNudge)
890 Vector3 translate(0, 0, 0);
891 translate[nDim] = fNudge;
893 GlobalSelectionSystem().translateSelected(translate);
896 void Selection_NudgeZ(float amount)
898 StringOutputStream command;
899 command << "nudgeSelected -axis z -amount " << amount;
900 UndoableCommand undo(command.c_str());
905 void Selection_MoveDown()
907 Selection_NudgeZ(-GetGridSize());
910 void Selection_MoveUp()
912 Selection_NudgeZ(GetGridSize());
915 void SceneSelectionChange(const Selectable& selectable)
920 SignalHandlerId Selection_boundsChanged;
922 void Selection_construct()
924 typedef FreeCaller1<const Selectable&, SceneSelectionChange> SceneSelectionChangeCaller;
925 GlobalSelectionSystem().addSelectionChangeCallback(SceneSelectionChangeCaller());
926 typedef FreeCaller1<const Selectable&, UpdateWorkzone_ForSelectionChanged> UpdateWorkzoneForSelectionChangedCaller;
927 GlobalSelectionSystem().addSelectionChangeCallback(UpdateWorkzoneForSelectionChangedCaller());
928 typedef FreeCaller<UpdateWorkzone_ForSelection> UpdateWorkzoneForSelectionCaller;
929 Selection_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(UpdateWorkzoneForSelectionCaller());
932 void Selection_destroy()
934 GlobalSceneGraph().removeBoundsChangedCallback(Selection_boundsChanged);
939 #include <gtk/gtkbox.h>
940 #include <gtk/gtkspinbutton.h>
941 #include <gtk/gtktable.h>
942 #include <gtk/gtklabel.h>
943 #include <gdk/gdkkeysyms.h>
946 inline Quaternion quaternion_for_euler_xyz_degrees(const Vector3& eulerXYZ)
949 return quaternion_for_matrix4_rotation(matrix4_rotation_for_euler_xyz_degrees(eulerXYZ));
951 return quaternion_multiplied_by_quaternion(
952 quaternion_multiplied_by_quaternion(
953 quaternion_for_z(degrees_to_radians(eulerXYZ[2])),
954 quaternion_for_y(degrees_to_radians(eulerXYZ[1]))
956 quaternion_for_x(degrees_to_radians(eulerXYZ[0]))
959 double cx = cos(degrees_to_radians(eulerXYZ[0] * 0.5));
960 double sx = sin(degrees_to_radians(eulerXYZ[0] * 0.5));
961 double cy = cos(degrees_to_radians(eulerXYZ[1] * 0.5));
962 double sy = sin(degrees_to_radians(eulerXYZ[1] * 0.5));
963 double cz = cos(degrees_to_radians(eulerXYZ[2] * 0.5));
964 double sz = sin(degrees_to_radians(eulerXYZ[2] * 0.5));
967 cz * cy * sx - sz * sy * cx,
968 cz * sy * cx + sz * cy * sx,
969 sz * cy * cx - cz * sy * sx,
970 cz * cy * cx + sz * sy * sx
983 static gboolean rotatedlg_apply (GtkWidget *widget, RotateDialog* rotateDialog)
987 eulerXYZ[0] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->x));
988 eulerXYZ[1] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->y));
989 eulerXYZ[2] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->z));
991 StringOutputStream command;
992 command << "rotateSelectedEulerXYZ -x " << eulerXYZ[0] << " -y " << eulerXYZ[1] << " -z " << eulerXYZ[2];
993 UndoableCommand undo(command.c_str());
995 GlobalSelectionSystem().rotateSelected(quaternion_for_euler_xyz_degrees(eulerXYZ));
999 static gboolean rotatedlg_cancel (GtkWidget *widget, RotateDialog* rotateDialog)
1001 gtk_widget_hide(GTK_WIDGET(rotateDialog->window));
1003 gtk_spin_button_set_value(rotateDialog->x, 0.0f); // reset to 0 on close
1004 gtk_spin_button_set_value(rotateDialog->y, 0.0f);
1005 gtk_spin_button_set_value(rotateDialog->z, 0.0f);
1010 static gboolean rotatedlg_ok (GtkWidget *widget, RotateDialog* rotateDialog)
1012 rotatedlg_apply(widget, rotateDialog);
1013 rotatedlg_cancel(widget, rotateDialog);
1017 static gboolean rotatedlg_delete (GtkWidget *widget, GdkEventAny *event, RotateDialog* rotateDialog)
1019 rotatedlg_cancel(widget, rotateDialog);
1023 RotateDialog g_rotate_dialog;
1026 if(g_rotate_dialog.window == NULL)
1028 g_rotate_dialog.window = create_dialog_window(MainFrame_getWindow(), "Arbitrary rotation", G_CALLBACK(rotatedlg_delete), &g_rotate_dialog);
1030 GtkAccelGroup* accel = gtk_accel_group_new();
1031 gtk_window_add_accel_group(g_rotate_dialog.window, accel);
1034 GtkHBox* hbox = create_dialog_hbox(4, 4);
1035 gtk_container_add(GTK_CONTAINER(g_rotate_dialog.window), GTK_WIDGET(hbox));
1037 GtkTable* table = create_dialog_table(3, 2, 4, 4);
1038 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
1040 GtkWidget* label = gtk_label_new (" X ");
1041 gtk_widget_show (label);
1042 gtk_table_attach(table, label, 0, 1, 0, 1,
1043 (GtkAttachOptions) (0),
1044 (GtkAttachOptions) (0), 0, 0);
1047 GtkWidget* label = gtk_label_new (" Y ");
1048 gtk_widget_show (label);
1049 gtk_table_attach(table, label, 0, 1, 1, 2,
1050 (GtkAttachOptions) (0),
1051 (GtkAttachOptions) (0), 0, 0);
1054 GtkWidget* label = gtk_label_new (" Z ");
1055 gtk_widget_show (label);
1056 gtk_table_attach(table, label, 0, 1, 2, 3,
1057 (GtkAttachOptions) (0),
1058 (GtkAttachOptions) (0), 0, 0);
1061 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 0));
1062 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
1063 gtk_widget_show(GTK_WIDGET(spin));
1064 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 0, 1,
1065 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1066 (GtkAttachOptions) (0), 0, 0);
1067 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
1068 gtk_spin_button_set_wrap(spin, TRUE);
1070 gtk_widget_grab_focus(GTK_WIDGET(spin));
1072 g_rotate_dialog.x = spin;
1075 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 0));
1076 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
1077 gtk_widget_show(GTK_WIDGET(spin));
1078 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 1, 2,
1079 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1080 (GtkAttachOptions) (0), 0, 0);
1081 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
1082 gtk_spin_button_set_wrap(spin, TRUE);
1084 g_rotate_dialog.y = spin;
1087 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 0));
1088 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
1089 gtk_widget_show(GTK_WIDGET(spin));
1090 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 2, 3,
1091 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1092 (GtkAttachOptions) (0), 0, 0);
1093 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
1094 gtk_spin_button_set_wrap(spin, TRUE);
1096 g_rotate_dialog.z = spin;
1100 GtkVBox* vbox = create_dialog_vbox(4);
1101 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
1103 GtkButton* button = create_dialog_button("OK", G_CALLBACK(rotatedlg_ok), &g_rotate_dialog);
1104 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1105 widget_make_default(GTK_WIDGET(button));
1106 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
1109 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(rotatedlg_cancel), &g_rotate_dialog);
1110 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1111 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
1114 GtkButton* button = create_dialog_button("Apply", G_CALLBACK(rotatedlg_apply), &g_rotate_dialog);
1115 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1121 gtk_widget_show(GTK_WIDGET(g_rotate_dialog.window));
1140 static gboolean scaledlg_apply (GtkWidget *widget, ScaleDialog* scaleDialog)
1144 sx = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (scaleDialog->x))));
1145 sy = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (scaleDialog->y))));
1146 sz = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (scaleDialog->z))));
1148 StringOutputStream command;
1149 command << "scaleSelected -x " << sx << " -y " << sy << " -z " << sz;
1150 UndoableCommand undo(command.c_str());
1152 Select_Scale(sx, sy, sz);
1157 static gboolean scaledlg_cancel (GtkWidget *widget, ScaleDialog* scaleDialog)
1159 gtk_widget_hide(GTK_WIDGET(scaleDialog->window));
1161 gtk_entry_set_text (GTK_ENTRY(scaleDialog->x), "1.0");
1162 gtk_entry_set_text (GTK_ENTRY(scaleDialog->y), "1.0");
1163 gtk_entry_set_text (GTK_ENTRY(scaleDialog->z), "1.0");
1168 static gboolean scaledlg_ok (GtkWidget *widget, ScaleDialog* scaleDialog)
1170 scaledlg_apply(widget, scaleDialog);
1171 scaledlg_cancel(widget, scaleDialog);
1175 static gboolean scaledlg_delete (GtkWidget *widget, GdkEventAny *event, ScaleDialog* scaleDialog)
1177 scaledlg_cancel(widget, scaleDialog);
1181 ScaleDialog g_scale_dialog;
1185 if(g_scale_dialog.window == NULL)
1187 g_scale_dialog.window = create_dialog_window(MainFrame_getWindow(), "Arbitrary scale", G_CALLBACK(scaledlg_delete), &g_scale_dialog);
1189 GtkAccelGroup* accel = gtk_accel_group_new();
1190 gtk_window_add_accel_group(g_scale_dialog.window, accel);
1193 GtkHBox* hbox = create_dialog_hbox(4, 4);
1194 gtk_container_add(GTK_CONTAINER(g_scale_dialog.window), GTK_WIDGET(hbox));
1196 GtkTable* table = create_dialog_table(3, 2, 4, 4);
1197 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
1199 GtkWidget* label = gtk_label_new (" X ");
1200 gtk_widget_show (label);
1201 gtk_table_attach(table, label, 0, 1, 0, 1,
1202 (GtkAttachOptions) (0),
1203 (GtkAttachOptions) (0), 0, 0);
1206 GtkWidget* label = gtk_label_new (" Y ");
1207 gtk_widget_show (label);
1208 gtk_table_attach(table, label, 0, 1, 1, 2,
1209 (GtkAttachOptions) (0),
1210 (GtkAttachOptions) (0), 0, 0);
1213 GtkWidget* label = gtk_label_new (" Z ");
1214 gtk_widget_show (label);
1215 gtk_table_attach(table, label, 0, 1, 2, 3,
1216 (GtkAttachOptions) (0),
1217 (GtkAttachOptions) (0), 0, 0);
1220 GtkWidget* entry = gtk_entry_new();
1221 gtk_entry_set_text (GTK_ENTRY(entry), "1.0");
1222 gtk_widget_show (entry);
1223 gtk_table_attach(table, entry, 1, 2, 0, 1,
1224 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1225 (GtkAttachOptions) (0), 0, 0);
1227 g_scale_dialog.x = entry;
1230 GtkWidget* entry = gtk_entry_new();
1231 gtk_entry_set_text (GTK_ENTRY(entry), "1.0");
1232 gtk_widget_show (entry);
1233 gtk_table_attach(table, entry, 1, 2, 1, 2,
1234 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1235 (GtkAttachOptions) (0), 0, 0);
1237 g_scale_dialog.y = entry;
1240 GtkWidget* entry = gtk_entry_new();
1241 gtk_entry_set_text (GTK_ENTRY(entry), "1.0");
1242 gtk_widget_show (entry);
1243 gtk_table_attach(table, entry, 1, 2, 2, 3,
1244 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1245 (GtkAttachOptions) (0), 0, 0);
1247 g_scale_dialog.z = entry;
1251 GtkVBox* vbox = create_dialog_vbox(4);
1252 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
1254 GtkButton* button = create_dialog_button("OK", G_CALLBACK(scaledlg_ok), &g_scale_dialog);
1255 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1256 widget_make_default(GTK_WIDGET(button));
1257 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
1260 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(scaledlg_cancel), &g_scale_dialog);
1261 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1262 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
1265 GtkButton* button = create_dialog_button("Apply", G_CALLBACK(scaledlg_apply), &g_scale_dialog);
1266 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1272 gtk_widget_show(GTK_WIDGET(g_scale_dialog.window));