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 "shaderlib.h"
36 #include "gtkutil/idledraw.h"
37 #include "gtkutil/dialog.h"
38 #include "gtkutil/widget.h"
39 #include "brushmanip.h"
40 #include "patchmanip.h"
41 #include "patchdialog.h"
42 #include "selection.h"
43 #include "texwindow.h"
45 #include "mainframe.h"
51 select_workzone_t g_select_workzone;
54 class DeleteSelected : public scene::Graph::Walker
56 mutable bool m_remove;
57 mutable bool m_removedChild;
60 : m_remove(false), m_removedChild(false)
63 bool pre(const scene::Path& path, scene::Instance& instance) const
65 m_removedChild = false;
67 Selectable* selectable = Instance_getSelectable(instance);
69 && selectable->isSelected()
71 && !path.top().get().isRoot())
79 void post(const scene::Path& path, scene::Instance& instance) const
83 m_removedChild = false;
85 // delete empty entities
86 Entity* entity = Node_getEntity(path.top());
88 && path.top().get_pointer() != Map_FindWorldspawn(g_map)
89 && Node_getTraversable(path.top())->empty())
97 if(Node_isEntity(path.parent()) != 0)
99 m_removedChild = true;
103 Path_deleteTop(path);
108 void Scene_DeleteSelected(scene::Graph& graph)
110 graph.traverse(DeleteSelected());
114 void Select_Delete (void)
116 Scene_DeleteSelected(GlobalSceneGraph());
119 class InvertSelectionWalker : public scene::Graph::Walker
121 SelectionSystem::EMode m_mode;
122 mutable Selectable* m_selectable;
124 InvertSelectionWalker(SelectionSystem::EMode mode)
125 : m_mode(mode), m_selectable(0)
128 bool pre(const scene::Path& path, scene::Instance& instance) const
130 Selectable* selectable = Instance_getSelectable(instance);
135 case SelectionSystem::eEntity:
136 if(Node_isEntity(path.top()) != 0)
138 m_selectable = path.top().get().visible() ? selectable : 0;
141 case SelectionSystem::ePrimitive:
142 m_selectable = path.top().get().visible() ? selectable : 0;
144 case SelectionSystem::eComponent:
150 void post(const scene::Path& path, scene::Instance& instance) const
152 if(m_selectable != 0)
154 m_selectable->setSelected(!m_selectable->isSelected());
160 void Scene_Invert_Selection(scene::Graph& graph)
162 graph.traverse(InvertSelectionWalker(GlobalSelectionSystem().Mode()));
167 Scene_Invert_Selection(GlobalSceneGraph());
170 class ExpandSelectionToEntitiesWalker : public scene::Graph::Walker
172 mutable std::size_t m_depth;
174 ExpandSelectionToEntitiesWalker() : m_depth(0)
177 bool pre(const scene::Path& path, scene::Instance& instance) const
180 if(m_depth == 2) // entity depth
182 // traverse and select children if any one is selected
183 return Node_getEntity(path.top())->isContainer() && instance.childSelected();
185 else if(m_depth == 3) // primitive depth
187 Instance_setSelected(instance, true);
192 void post(const scene::Path& path, scene::Instance& instance) const
198 void Scene_ExpandSelectionToEntities()
200 GlobalSceneGraph().traverse(ExpandSelectionToEntitiesWalker());
206 void Selection_UpdateWorkzone()
208 if(GlobalSelectionSystem().countSelected() != 0)
210 Select_GetBounds(g_select_workzone.d_work_min, g_select_workzone.d_work_max);
213 typedef FreeCaller<Selection_UpdateWorkzone> SelectionUpdateWorkzoneCaller;
215 IdleDraw g_idleWorkzone = IdleDraw(SelectionUpdateWorkzoneCaller());
218 const select_workzone_t& Select_getWorkZone()
220 g_idleWorkzone.flush();
221 return g_select_workzone;
224 void UpdateWorkzone_ForSelection()
226 g_idleWorkzone.queueDraw();
229 // update the workzone to the current selection
230 void UpdateWorkzone_ForSelection(const Selectable& selectable)
232 if(selectable.isSelected())
234 UpdateWorkzone_ForSelection();
238 void Select_SetShader(const char* shader)
240 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
242 Scene_BrushSetShader_Selected(GlobalSceneGraph(), shader);
243 Scene_PatchSetShader_Selected(GlobalSceneGraph(), shader);
245 Scene_BrushSetShader_Component_Selected(GlobalSceneGraph(), shader);
248 void Select_SetTexdef(const TextureProjection& projection)
250 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
252 Scene_BrushSetTexdef_Selected(GlobalSceneGraph(), projection);
254 Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection);
257 void Select_SetFlags(const ContentsFlagsValue& flags)
259 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
261 Scene_BrushSetFlags_Selected(GlobalSceneGraph(), flags);
263 Scene_BrushSetFlags_Component_Selected(GlobalSceneGraph(), flags);
266 void Select_GetBounds (Vector3& mins, Vector3& maxs)
269 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
270 maxs = vector3_added(bounds.origin, bounds.extents);
271 mins = vector3_subtracted(bounds.origin, bounds.extents);
274 void Select_GetMid (Vector3& mid)
277 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
278 mid = vector3_snapped(bounds.origin);
282 void Select_FlipAxis (int axis)
284 Vector3 flip(1, 1, 1);
286 GlobalSelectionSystem().scaleSelected(flip);
290 void Select_Scale(float x, float y, float z)
292 GlobalSelectionSystem().scaleSelected(Vector3(x, y, z));
308 inline Matrix4 matrix4_rotation_for_axis90(axis_t axis, sign_t sign)
313 if(sign == eSignPositive)
315 return matrix4_rotation_for_sincos_x(1, 0);
319 return matrix4_rotation_for_sincos_x(-1, 0);
322 if(sign == eSignPositive)
324 return matrix4_rotation_for_sincos_y(1, 0);
328 return matrix4_rotation_for_sincos_y(-1, 0);
330 default://case eAxisZ:
331 if(sign == eSignPositive)
333 return matrix4_rotation_for_sincos_z(1, 0);
337 return matrix4_rotation_for_sincos_z(-1, 0);
342 inline void matrix4_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign)
344 matrix4_multiply_by_matrix4(matrix, matrix4_rotation_for_axis90(axis, sign));
347 inline void matrix4_pivoted_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign, const Vector3& pivotpoint)
349 matrix4_translate_by_vec3(matrix, pivotpoint);
350 matrix4_rotate_by_axis90(matrix, axis, sign);
351 matrix4_translate_by_vec3(matrix, vector3_negated(pivotpoint));
354 inline Quaternion quaternion_for_axis90(axis_t axis, sign_t sign)
360 if(sign == eSignPositive)
362 return Quaternion(c_half_sqrt2f, 0, 0, c_half_sqrt2f);
366 return Quaternion(-c_half_sqrt2f, 0, 0, -c_half_sqrt2f);
369 if(sign == eSignPositive)
371 return Quaternion(0, c_half_sqrt2f, 0, c_half_sqrt2f);
375 return Quaternion(0, -c_half_sqrt2f, 0, -c_half_sqrt2f);
377 default://case eAxisZ:
378 if(sign == eSignPositive)
380 return Quaternion(0, 0, c_half_sqrt2f, c_half_sqrt2f);
384 return Quaternion(0, 0, -c_half_sqrt2f, -c_half_sqrt2f);
388 quaternion_for_matrix4_rotation(matrix4_rotation_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
392 void Select_RotateAxis (int axis, float deg)
394 if(fabs(deg) == 90.f)
396 GlobalSelectionSystem().rotateSelected(quaternion_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
403 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_x_degrees(deg)));
406 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_y_degrees(deg)));
409 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_z_degrees(deg)));
416 void Select_ShiftTexture(float x, float y)
418 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
420 Scene_BrushShiftTexdef_Selected(GlobalSceneGraph(), x, y);
421 Scene_PatchTranslateTexture_Selected(GlobalSceneGraph(), x, y);
423 //globalOutputStream() << "shift selected face textures: s=" << x << " t=" << y << '\n';
424 Scene_BrushShiftTexdef_Component_Selected(GlobalSceneGraph(), x, y);
427 void Select_ScaleTexture(float x, float y)
429 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
431 Scene_BrushScaleTexdef_Selected(GlobalSceneGraph(), x, y);
432 Scene_PatchScaleTexture_Selected(GlobalSceneGraph(), x, y);
434 Scene_BrushScaleTexdef_Component_Selected(GlobalSceneGraph(), x, y);
437 void Select_RotateTexture(float amt)
439 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
441 Scene_BrushRotateTexdef_Selected(GlobalSceneGraph(), amt);
442 Scene_PatchRotateTexture_Selected(GlobalSceneGraph(), amt);
444 Scene_BrushRotateTexdef_Component_Selected(GlobalSceneGraph(), amt);
447 // TTimo modified to handle shader architecture:
448 // expects shader names at input, comparison relies on shader names .. texture names no longer relevant
449 void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected)
451 if(!texdef_name_valid(pFind))
453 globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pFind << "', aborted\n";
456 if(!texdef_name_valid(pReplace))
458 globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pReplace << "', aborted\n";
462 StringOutputStream command;
463 command << "textureFindReplace -find " << pFind << " -replace " << pReplace;
464 UndoableCommand undo(command.c_str());
468 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
470 Scene_BrushFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
471 Scene_PatchFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
473 Scene_BrushFindReplaceShader_Component_Selected(GlobalSceneGraph(), pFind, pReplace);
477 Scene_BrushFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
478 Scene_PatchFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
482 typedef std::vector<const char*> Classnames;
484 bool classnames_match_entity(const Classnames& classnames, Entity* entity)
486 for(Classnames::const_iterator i = classnames.begin(); i != classnames.end(); ++i)
488 if(string_equal(entity->getKeyValue("classname"), *i))
496 class EntityFindByClassnameWalker : public scene::Graph::Walker
498 const Classnames& m_classnames;
500 EntityFindByClassnameWalker(const Classnames& classnames)
501 : m_classnames(classnames)
504 bool pre(const scene::Path& path, scene::Instance& instance) const
506 Entity* entity = Node_getEntity(path.top());
508 && classnames_match_entity(m_classnames, entity))
510 Instance_getSelectable(instance)->setSelected(true);
516 void Scene_EntitySelectByClassnames(scene::Graph& graph, const Classnames& classnames)
518 graph.traverse(EntityFindByClassnameWalker(classnames));
521 class EntityGetSelectedClassnamesWalker : public scene::Graph::Walker
523 Classnames& m_classnames;
525 EntityGetSelectedClassnamesWalker(Classnames& classnames)
526 : m_classnames(classnames)
529 bool pre(const scene::Path& path, scene::Instance& instance) const
531 Selectable* selectable = Instance_getSelectable(instance);
533 && selectable->isSelected())
535 Entity* entity = Node_getEntity(path.top());
538 m_classnames.push_back(entity->getKeyValue("classname"));
545 void Scene_EntityGetClassnames(scene::Graph& graph, Classnames& classnames)
547 graph.traverse(EntityGetSelectedClassnamesWalker(classnames));
550 void Select_AllOfType()
552 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent)
554 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace)
556 GlobalSelectionSystem().setSelectedAllComponents(false);
557 Scene_BrushSelectByShader_Component(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
562 Classnames classnames;
563 Scene_EntityGetClassnames(GlobalSceneGraph(), classnames);
564 GlobalSelectionSystem().setSelectedAll(false);
565 if(!classnames.empty())
567 Scene_EntitySelectByClassnames(GlobalSceneGraph(), classnames);
571 Scene_BrushSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
572 Scene_PatchSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
579 void Select_FitTexture(float horizontal, float vertical)
581 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
583 Scene_BrushFitTexture_Selected(GlobalSceneGraph(), horizontal, vertical);
585 Scene_BrushFitTexture_Component_Selected(GlobalSceneGraph(), horizontal, vertical);
590 inline void hide_node(scene::Node& node, bool hide)
593 ? node.enable(scene::Node::eHidden)
594 : node.disable(scene::Node::eHidden);
597 class HideSelectedWalker : public scene::Graph::Walker
601 HideSelectedWalker(bool hide)
605 bool pre(const scene::Path& path, scene::Instance& instance) const
607 Selectable* selectable = Instance_getSelectable(instance);
609 && selectable->isSelected())
611 hide_node(path.top(), m_hide);
617 void Scene_Hide_Selected(bool hide)
619 GlobalSceneGraph().traverse(HideSelectedWalker(hide));
624 Scene_Hide_Selected(true);
631 GlobalSelectionSystem().setSelectedAll(false);
635 class HideAllWalker : public scene::Graph::Walker
639 HideAllWalker(bool hide)
643 bool pre(const scene::Path& path, scene::Instance& instance) const
645 hide_node(path.top(), m_hide);
650 void Scene_Hide_All(bool hide)
652 GlobalSceneGraph().traverse(HideAllWalker(hide));
655 void Select_ShowAllHidden()
657 Scene_Hide_All(false);
663 void Selection_Flipx()
665 UndoableCommand undo("mirrorSelected -axis x");
669 void Selection_Flipy()
671 UndoableCommand undo("mirrorSelected -axis y");
675 void Selection_Flipz()
677 UndoableCommand undo("mirrorSelected -axis z");
681 void Selection_Rotatex()
683 UndoableCommand undo("rotateSelected -axis x -angle -90");
684 Select_RotateAxis(0,-90);
687 void Selection_Rotatey()
689 UndoableCommand undo("rotateSelected -axis y -angle 90");
690 Select_RotateAxis(1, 90);
693 void Selection_Rotatez()
695 UndoableCommand undo("rotateSelected -axis z -angle -90");
696 Select_RotateAxis(2,-90);
701 void Nudge(int nDim, float fNudge)
703 Vector3 translate(0, 0, 0);
704 translate[nDim] = fNudge;
706 GlobalSelectionSystem().translateSelected(translate);
709 void Selection_NudgeZ(float amount)
711 StringOutputStream command;
712 command << "nudgeSelected -axis z -amount " << amount;
713 UndoableCommand undo(command.c_str());
718 void Selection_MoveDown()
720 Selection_NudgeZ(-GetGridSize());
723 void Selection_MoveUp()
725 Selection_NudgeZ(GetGridSize());
728 void SceneSelectionChange(const Selectable& selectable)
733 void Selection_construct()
735 GlobalSelectionSystem().addSelectionChangeCallback(FreeCaller1<const Selectable&, SceneSelectionChange>());
736 GlobalSelectionSystem().addSelectionChangeCallback(FreeCaller1<const Selectable&, UpdateWorkzone_ForSelection>());
737 GlobalSceneGraph().addBoundsChangedCallback(FreeCaller<UpdateWorkzone_ForSelection>());
740 void Selection_destroy()
742 GlobalSceneGraph().removeBoundsChangedCallback(FreeCaller<UpdateWorkzone_ForSelection>());
747 #include <gtk/gtkbox.h>
748 #include <gtk/gtkspinbutton.h>
749 #include <gtk/gtktable.h>
750 #include <gtk/gtklabel.h>
751 #include <gdk/gdkkeysyms.h>
753 inline Quaternion quaternion_for_euler_xyz_degrees(const Vector3& eulerXYZ)
755 double cx = cos(degrees_to_radians(eulerXYZ[0] * 0.5));
756 double sx = sin(degrees_to_radians(eulerXYZ[0] * 0.5));
757 double cy = cos(degrees_to_radians(eulerXYZ[1] * 0.5));
758 double sy = sin(degrees_to_radians(eulerXYZ[1] * 0.5));
759 double cz = cos(degrees_to_radians(eulerXYZ[2] * 0.5));
760 double sz = sin(degrees_to_radians(eulerXYZ[2] * 0.5));
763 static_cast<float>(cx * sy * cz - sx * cy * sz),
764 static_cast<float>(cx * sy * sz + sx * cy * cz),
765 static_cast<float>(cx * cy * sz - sx * sy * cz),
766 static_cast<float>(cx * cy * cz + sx * sy * sz)
777 static void rotatedlg_apply (GtkWidget *widget, RotateDialog* rotateDialog)
781 eulerXYZ[0] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->x));
782 gtk_spin_button_set_value(rotateDialog->x, 0.0f); // reset to 0 on Apply
784 eulerXYZ[1] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->y));
785 gtk_spin_button_set_value(rotateDialog->y, 0.0f);
787 eulerXYZ[2] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->z));
788 gtk_spin_button_set_value(rotateDialog->z, 0.0f);
790 StringOutputStream command;
791 command << "rotateSelectedEulerXYZ -x " << eulerXYZ[0] << " -y " << eulerXYZ[1] << " -z " << eulerXYZ[2];
792 UndoableCommand undo(command.c_str());
794 GlobalSelectionSystem().rotateSelected(quaternion_for_euler_xyz_degrees(eulerXYZ));
800 RotateDialog rotateDialog;
802 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Arbitrary rotation", G_CALLBACK(dialog_delete_callback), &dialog);
804 GtkAccelGroup* accel = gtk_accel_group_new();
805 gtk_window_add_accel_group(window, accel);
808 GtkHBox* hbox = create_dialog_hbox(4, 4);
809 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
811 GtkTable* table = create_dialog_table(3, 2, 4, 4);
812 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
814 GtkWidget* label = gtk_label_new (" X ");
815 gtk_widget_show (label);
816 gtk_table_attach(table, label, 0, 1, 0, 1,
817 (GtkAttachOptions) (0),
818 (GtkAttachOptions) (0), 0, 0);
821 GtkWidget* label = gtk_label_new (" Y ");
822 gtk_widget_show (label);
823 gtk_table_attach(table, label, 0, 1, 1, 2,
824 (GtkAttachOptions) (0),
825 (GtkAttachOptions) (0), 0, 0);
828 GtkWidget* label = gtk_label_new (" Z ");
829 gtk_widget_show (label);
830 gtk_table_attach(table, label, 0, 1, 2, 3,
831 (GtkAttachOptions) (0),
832 (GtkAttachOptions) (0), 0, 0);
835 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
836 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
837 gtk_widget_show(GTK_WIDGET(spin));
838 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 0, 1,
839 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
840 (GtkAttachOptions) (0), 0, 0);
841 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
842 gtk_spin_button_set_wrap(spin, TRUE);
844 gtk_widget_grab_focus(GTK_WIDGET(spin));
846 rotateDialog.x = spin;
849 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
850 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
851 gtk_widget_show(GTK_WIDGET(spin));
852 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 1, 2,
853 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
854 (GtkAttachOptions) (0), 0, 0);
855 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
856 gtk_spin_button_set_wrap(spin, TRUE);
858 rotateDialog.y = spin;
861 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
862 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
863 gtk_widget_show(GTK_WIDGET(spin));
864 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 2, 3,
865 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
866 (GtkAttachOptions) (0), 0, 0);
867 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
868 gtk_spin_button_set_wrap(spin, TRUE);
870 rotateDialog.z = spin;
874 GtkVBox* vbox = create_dialog_vbox(4);
875 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
877 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
878 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
879 widget_make_default(GTK_WIDGET(button));
880 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
883 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
884 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
885 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
888 GtkButton* button = create_dialog_button("Apply", G_CALLBACK(rotatedlg_apply), &rotateDialog);
889 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
894 if(modal_dialog_show(window, dialog) == eIDOK)
896 rotatedlg_apply(0, &rotateDialog);
899 gtk_widget_destroy(GTK_WIDGET(window));
909 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Scale", G_CALLBACK(dialog_delete_callback), &dialog);
911 GtkAccelGroup* accel = gtk_accel_group_new();
912 gtk_window_add_accel_group(window, accel);
915 GtkHBox* hbox = create_dialog_hbox(4, 4);
916 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
918 GtkTable* table = create_dialog_table(3, 2, 4, 4);
919 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
921 GtkWidget* label = gtk_label_new ("X:");
922 gtk_widget_show (label);
923 gtk_table_attach(table, label, 0, 1, 0, 1,
924 (GtkAttachOptions) (GTK_FILL),
925 (GtkAttachOptions) (0), 0, 0);
926 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
929 GtkWidget* label = gtk_label_new ("Y:");
930 gtk_widget_show (label);
931 gtk_table_attach(table, label, 0, 1, 1, 2,
932 (GtkAttachOptions) (GTK_FILL),
933 (GtkAttachOptions) (0), 0, 0);
934 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
937 GtkWidget* label = gtk_label_new ("Z:");
938 gtk_widget_show (label);
939 gtk_table_attach(table, label, 0, 1, 2, 3,
940 (GtkAttachOptions) (GTK_FILL),
941 (GtkAttachOptions) (0), 0, 0);
942 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
945 GtkWidget* entry = gtk_entry_new();
946 gtk_widget_show (entry);
947 gtk_table_attach(table, entry, 1, 2, 0, 1,
948 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
949 (GtkAttachOptions) (0), 0, 0);
951 gtk_widget_grab_focus(entry);
956 GtkWidget* entry = gtk_entry_new();
957 gtk_widget_show (entry);
958 gtk_table_attach(table, entry, 1, 2, 1, 2,
959 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
960 (GtkAttachOptions) (0), 0, 0);
965 GtkWidget* entry = gtk_entry_new();
966 gtk_widget_show (entry);
967 gtk_table_attach(table, entry, 1, 2, 2, 3,
968 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
969 (GtkAttachOptions) (0), 0, 0);
975 GtkVBox* vbox = create_dialog_vbox(4);
976 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
978 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
979 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
980 widget_make_default(GTK_WIDGET(button));
981 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
984 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
985 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
986 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
992 gtk_entry_set_text (GTK_ENTRY (x), "1.0");
993 gtk_entry_set_text (GTK_ENTRY (y), "1.0");
994 gtk_entry_set_text (GTK_ENTRY (z), "1.0");
996 if(modal_dialog_show(window, dialog) == eIDOK)
999 sx = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (x))));
1000 sy = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (y))));
1001 sz = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (z))));
1003 if (sx > 0 && sy > 0 && sz > 0)
1005 StringOutputStream command;
1006 command << "scaleSelected -x " << sx << " -y " << sy << " -z " << sz;
1007 UndoableCommand undo(command.c_str());
1009 Select_Scale(sx, sy, sz);
1013 globalOutputStream() << "Warning.. Tried to scale by a zero value.";
1017 gtk_widget_destroy(GTK_WIDGET(window));