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"
41 #include "patchmanip.h"
42 #include "patchdialog.h"
43 #include "selection.h"
44 #include "texwindow.h"
46 #include "mainframe.h"
52 select_workzone_t g_select_workzone;
55 class DeleteSelected : public scene::Graph::Walker
57 mutable bool m_remove;
58 mutable bool m_removedChild;
61 : m_remove(false), m_removedChild(false)
64 bool pre(const scene::Path& path, scene::Instance& instance) const
66 m_removedChild = false;
68 Selectable* selectable = Instance_getSelectable(instance);
70 && selectable->isSelected()
72 && !path.top().get().isRoot())
80 void post(const scene::Path& path, scene::Instance& instance) const
84 m_removedChild = false;
86 // delete empty entities
87 Entity* entity = Node_getEntity(path.top());
89 && path.top().get_pointer() != Map_FindWorldspawn(g_map)
90 && Node_getTraversable(path.top())->empty())
98 if(Node_isEntity(path.parent()) != 0)
100 m_removedChild = true;
104 Path_deleteTop(path);
109 void Scene_DeleteSelected(scene::Graph& graph)
111 graph.traverse(DeleteSelected());
115 void Select_Delete (void)
117 Scene_DeleteSelected(GlobalSceneGraph());
120 class InvertSelectionWalker : public scene::Graph::Walker
122 SelectionSystem::EMode m_mode;
123 mutable Selectable* m_selectable;
125 InvertSelectionWalker(SelectionSystem::EMode mode)
126 : m_mode(mode), m_selectable(0)
129 bool pre(const scene::Path& path, scene::Instance& instance) const
131 Selectable* selectable = Instance_getSelectable(instance);
136 case SelectionSystem::eEntity:
137 if(Node_isEntity(path.top()) != 0)
139 m_selectable = path.top().get().visible() ? selectable : 0;
142 case SelectionSystem::ePrimitive:
143 m_selectable = path.top().get().visible() ? selectable : 0;
145 case SelectionSystem::eComponent:
151 void post(const scene::Path& path, scene::Instance& instance) const
153 if(m_selectable != 0)
155 m_selectable->setSelected(!m_selectable->isSelected());
161 void Scene_Invert_Selection(scene::Graph& graph)
163 graph.traverse(InvertSelectionWalker(GlobalSelectionSystem().Mode()));
168 Scene_Invert_Selection(GlobalSceneGraph());
171 class ExpandSelectionToEntitiesWalker : public scene::Graph::Walker
173 mutable std::size_t m_depth;
175 ExpandSelectionToEntitiesWalker() : m_depth(0)
178 bool pre(const scene::Path& path, scene::Instance& instance) const
181 if(m_depth == 2) // entity depth
183 // traverse and select children if any one is selected
184 return Node_getEntity(path.top())->isContainer() && instance.childSelected();
186 else if(m_depth == 3) // primitive depth
188 Instance_setSelected(instance, true);
193 void post(const scene::Path& path, scene::Instance& instance) const
199 void Scene_ExpandSelectionToEntities()
201 GlobalSceneGraph().traverse(ExpandSelectionToEntitiesWalker());
207 void Selection_UpdateWorkzone()
209 if(GlobalSelectionSystem().countSelected() != 0)
211 Select_GetBounds(g_select_workzone.d_work_min, g_select_workzone.d_work_max);
214 typedef FreeCaller<Selection_UpdateWorkzone> SelectionUpdateWorkzoneCaller;
216 IdleDraw g_idleWorkzone = IdleDraw(SelectionUpdateWorkzoneCaller());
219 const select_workzone_t& Select_getWorkZone()
221 g_idleWorkzone.flush();
222 return g_select_workzone;
225 void UpdateWorkzone_ForSelection()
227 g_idleWorkzone.queueDraw();
230 // update the workzone to the current selection
231 void UpdateWorkzone_ForSelectionChanged(const Selectable& selectable)
233 if(selectable.isSelected())
235 UpdateWorkzone_ForSelection();
239 void Select_SetShader(const char* shader)
241 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
243 Scene_BrushSetShader_Selected(GlobalSceneGraph(), shader);
244 Scene_PatchSetShader_Selected(GlobalSceneGraph(), shader);
246 Scene_BrushSetShader_Component_Selected(GlobalSceneGraph(), shader);
249 void Select_SetTexdef(const TextureProjection& projection)
251 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
253 Scene_BrushSetTexdef_Selected(GlobalSceneGraph(), projection);
255 Scene_BrushSetTexdef_Component_Selected(GlobalSceneGraph(), projection);
258 void Select_SetFlags(const ContentsFlagsValue& flags)
260 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
262 Scene_BrushSetFlags_Selected(GlobalSceneGraph(), flags);
264 Scene_BrushSetFlags_Component_Selected(GlobalSceneGraph(), flags);
267 void Select_GetBounds (Vector3& mins, Vector3& maxs)
270 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
271 maxs = vector3_added(bounds.origin, bounds.extents);
272 mins = vector3_subtracted(bounds.origin, bounds.extents);
275 void Select_GetMid (Vector3& mid)
278 Scene_BoundsSelected(GlobalSceneGraph(), bounds);
279 mid = vector3_snapped(bounds.origin);
283 void Select_FlipAxis (int axis)
285 Vector3 flip(1, 1, 1);
287 GlobalSelectionSystem().scaleSelected(flip);
291 void Select_Scale(float x, float y, float z)
293 GlobalSelectionSystem().scaleSelected(Vector3(x, y, z));
309 inline Matrix4 matrix4_rotation_for_axis90(axis_t axis, sign_t sign)
314 if(sign == eSignPositive)
316 return matrix4_rotation_for_sincos_x(1, 0);
320 return matrix4_rotation_for_sincos_x(-1, 0);
323 if(sign == eSignPositive)
325 return matrix4_rotation_for_sincos_y(1, 0);
329 return matrix4_rotation_for_sincos_y(-1, 0);
331 default://case eAxisZ:
332 if(sign == eSignPositive)
334 return matrix4_rotation_for_sincos_z(1, 0);
338 return matrix4_rotation_for_sincos_z(-1, 0);
343 inline void matrix4_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign)
345 matrix4_multiply_by_matrix4(matrix, matrix4_rotation_for_axis90(axis, sign));
348 inline void matrix4_pivoted_rotate_by_axis90(Matrix4& matrix, axis_t axis, sign_t sign, const Vector3& pivotpoint)
350 matrix4_translate_by_vec3(matrix, pivotpoint);
351 matrix4_rotate_by_axis90(matrix, axis, sign);
352 matrix4_translate_by_vec3(matrix, vector3_negated(pivotpoint));
355 inline Quaternion quaternion_for_axis90(axis_t axis, sign_t sign)
361 if(sign == eSignPositive)
363 return Quaternion(c_half_sqrt2f, 0, 0, c_half_sqrt2f);
367 return Quaternion(-c_half_sqrt2f, 0, 0, -c_half_sqrt2f);
370 if(sign == eSignPositive)
372 return Quaternion(0, c_half_sqrt2f, 0, c_half_sqrt2f);
376 return Quaternion(0, -c_half_sqrt2f, 0, -c_half_sqrt2f);
378 default://case eAxisZ:
379 if(sign == eSignPositive)
381 return Quaternion(0, 0, c_half_sqrt2f, c_half_sqrt2f);
385 return Quaternion(0, 0, -c_half_sqrt2f, -c_half_sqrt2f);
389 quaternion_for_matrix4_rotation(matrix4_rotation_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
393 void Select_RotateAxis (int axis, float deg)
395 if(fabs(deg) == 90.f)
397 GlobalSelectionSystem().rotateSelected(quaternion_for_axis90((axis_t)axis, (deg > 0) ? eSignPositive : eSignNegative));
404 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_x_degrees(deg)));
407 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_y_degrees(deg)));
410 GlobalSelectionSystem().rotateSelected(quaternion_for_matrix4_rotation(matrix4_rotation_for_z_degrees(deg)));
417 void Select_ShiftTexture(float x, float y)
419 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
421 Scene_BrushShiftTexdef_Selected(GlobalSceneGraph(), x, y);
422 Scene_PatchTranslateTexture_Selected(GlobalSceneGraph(), x, y);
424 //globalOutputStream() << "shift selected face textures: s=" << x << " t=" << y << '\n';
425 Scene_BrushShiftTexdef_Component_Selected(GlobalSceneGraph(), x, y);
428 void Select_ScaleTexture(float x, float y)
430 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
432 Scene_BrushScaleTexdef_Selected(GlobalSceneGraph(), x, y);
433 Scene_PatchScaleTexture_Selected(GlobalSceneGraph(), x, y);
435 Scene_BrushScaleTexdef_Component_Selected(GlobalSceneGraph(), x, y);
438 void Select_RotateTexture(float amt)
440 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
442 Scene_BrushRotateTexdef_Selected(GlobalSceneGraph(), amt);
443 Scene_PatchRotateTexture_Selected(GlobalSceneGraph(), amt);
445 Scene_BrushRotateTexdef_Component_Selected(GlobalSceneGraph(), amt);
448 // TTimo modified to handle shader architecture:
449 // expects shader names at input, comparison relies on shader names .. texture names no longer relevant
450 void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected)
452 if(!texdef_name_valid(pFind))
454 globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pFind << "', aborted\n";
457 if(!texdef_name_valid(pReplace))
459 globalErrorStream() << "FindReplaceTextures: invalid texture name: '" << pReplace << "', aborted\n";
463 StringOutputStream command;
464 command << "textureFindReplace -find " << pFind << " -replace " << pReplace;
465 UndoableCommand undo(command.c_str());
469 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
471 Scene_BrushFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
472 Scene_PatchFindReplaceShader_Selected(GlobalSceneGraph(), pFind, pReplace);
474 Scene_BrushFindReplaceShader_Component_Selected(GlobalSceneGraph(), pFind, pReplace);
478 Scene_BrushFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
479 Scene_PatchFindReplaceShader(GlobalSceneGraph(), pFind, pReplace);
483 typedef std::vector<const char*> Classnames;
485 bool classnames_match_entity(const Classnames& classnames, Entity* entity)
487 for(Classnames::const_iterator i = classnames.begin(); i != classnames.end(); ++i)
489 if(string_equal(entity->getKeyValue("classname"), *i))
497 class EntityFindByClassnameWalker : public scene::Graph::Walker
499 const Classnames& m_classnames;
501 EntityFindByClassnameWalker(const Classnames& classnames)
502 : m_classnames(classnames)
505 bool pre(const scene::Path& path, scene::Instance& instance) const
507 Entity* entity = Node_getEntity(path.top());
509 && classnames_match_entity(m_classnames, entity))
511 Instance_getSelectable(instance)->setSelected(true);
517 void Scene_EntitySelectByClassnames(scene::Graph& graph, const Classnames& classnames)
519 graph.traverse(EntityFindByClassnameWalker(classnames));
522 class EntityGetSelectedClassnamesWalker : public scene::Graph::Walker
524 Classnames& m_classnames;
526 EntityGetSelectedClassnamesWalker(Classnames& classnames)
527 : m_classnames(classnames)
530 bool pre(const scene::Path& path, scene::Instance& instance) const
532 Selectable* selectable = Instance_getSelectable(instance);
534 && selectable->isSelected())
536 Entity* entity = Node_getEntity(path.top());
539 m_classnames.push_back(entity->getKeyValue("classname"));
546 void Scene_EntityGetClassnames(scene::Graph& graph, Classnames& classnames)
548 graph.traverse(EntityGetSelectedClassnamesWalker(classnames));
551 void Select_AllOfType()
553 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent)
555 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace)
557 GlobalSelectionSystem().setSelectedAllComponents(false);
558 Scene_BrushSelectByShader_Component(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
563 Classnames classnames;
564 Scene_EntityGetClassnames(GlobalSceneGraph(), classnames);
565 GlobalSelectionSystem().setSelectedAll(false);
566 if(!classnames.empty())
568 Scene_EntitySelectByClassnames(GlobalSceneGraph(), classnames);
572 Scene_BrushSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
573 Scene_PatchSelectByShader(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
580 void Select_FitTexture(float horizontal, float vertical)
582 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
584 Scene_BrushFitTexture_Selected(GlobalSceneGraph(), horizontal, vertical);
586 Scene_BrushFitTexture_Component_Selected(GlobalSceneGraph(), horizontal, vertical);
591 inline void hide_node(scene::Node& node, bool hide)
594 ? node.enable(scene::Node::eHidden)
595 : node.disable(scene::Node::eHidden);
598 class HideSelectedWalker : public scene::Graph::Walker
602 HideSelectedWalker(bool hide)
606 bool pre(const scene::Path& path, scene::Instance& instance) const
608 Selectable* selectable = Instance_getSelectable(instance);
610 && selectable->isSelected())
612 hide_node(path.top(), m_hide);
618 void Scene_Hide_Selected(bool hide)
620 GlobalSceneGraph().traverse(HideSelectedWalker(hide));
625 Scene_Hide_Selected(true);
632 GlobalSelectionSystem().setSelectedAll(false);
636 class HideAllWalker : public scene::Graph::Walker
640 HideAllWalker(bool hide)
644 bool pre(const scene::Path& path, scene::Instance& instance) const
646 hide_node(path.top(), m_hide);
651 void Scene_Hide_All(bool hide)
653 GlobalSceneGraph().traverse(HideAllWalker(hide));
656 void Select_ShowAllHidden()
658 Scene_Hide_All(false);
664 void Selection_Flipx()
666 UndoableCommand undo("mirrorSelected -axis x");
670 void Selection_Flipy()
672 UndoableCommand undo("mirrorSelected -axis y");
676 void Selection_Flipz()
678 UndoableCommand undo("mirrorSelected -axis z");
682 void Selection_Rotatex()
684 UndoableCommand undo("rotateSelected -axis x -angle -90");
685 Select_RotateAxis(0,-90);
688 void Selection_Rotatey()
690 UndoableCommand undo("rotateSelected -axis y -angle 90");
691 Select_RotateAxis(1, 90);
694 void Selection_Rotatez()
696 UndoableCommand undo("rotateSelected -axis z -angle -90");
697 Select_RotateAxis(2,-90);
702 void Nudge(int nDim, float fNudge)
704 Vector3 translate(0, 0, 0);
705 translate[nDim] = fNudge;
707 GlobalSelectionSystem().translateSelected(translate);
710 void Selection_NudgeZ(float amount)
712 StringOutputStream command;
713 command << "nudgeSelected -axis z -amount " << amount;
714 UndoableCommand undo(command.c_str());
719 void Selection_MoveDown()
721 Selection_NudgeZ(-GetGridSize());
724 void Selection_MoveUp()
726 Selection_NudgeZ(GetGridSize());
729 void SceneSelectionChange(const Selectable& selectable)
734 SignalHandlerId Selection_boundsChanged;
736 void Selection_construct()
738 typedef FreeCaller1<const Selectable&, SceneSelectionChange> SceneSelectionChangeCaller;
739 GlobalSelectionSystem().addSelectionChangeCallback(SceneSelectionChangeCaller());
740 typedef FreeCaller1<const Selectable&, UpdateWorkzone_ForSelectionChanged> UpdateWorkzoneForSelectionChangedCaller;
741 GlobalSelectionSystem().addSelectionChangeCallback(UpdateWorkzoneForSelectionChangedCaller());
742 typedef FreeCaller<UpdateWorkzone_ForSelection> UpdateWorkzoneForSelectionCaller;
743 Selection_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback(UpdateWorkzoneForSelectionCaller());
746 void Selection_destroy()
748 GlobalSceneGraph().removeBoundsChangedCallback(Selection_boundsChanged);
753 #include <gtk/gtkbox.h>
754 #include <gtk/gtkspinbutton.h>
755 #include <gtk/gtktable.h>
756 #include <gtk/gtklabel.h>
757 #include <gdk/gdkkeysyms.h>
760 inline Quaternion quaternion_for_euler_xyz_degrees(const Vector3& eulerXYZ)
763 return quaternion_for_matrix4_rotation(matrix4_rotation_for_euler_xyz_degrees(eulerXYZ));
765 return quaternion_multiplied_by_quaternion(
766 quaternion_multiplied_by_quaternion(
767 quaternion_for_z(degrees_to_radians(eulerXYZ[2])),
768 quaternion_for_y(degrees_to_radians(eulerXYZ[1]))
770 quaternion_for_x(degrees_to_radians(eulerXYZ[0]))
773 double cx = cos(degrees_to_radians(eulerXYZ[0] * 0.5));
774 double sx = sin(degrees_to_radians(eulerXYZ[0] * 0.5));
775 double cy = cos(degrees_to_radians(eulerXYZ[1] * 0.5));
776 double sy = sin(degrees_to_radians(eulerXYZ[1] * 0.5));
777 double cz = cos(degrees_to_radians(eulerXYZ[2] * 0.5));
778 double sz = sin(degrees_to_radians(eulerXYZ[2] * 0.5));
781 cz * cy * sx - sz * sy * cx,
782 cz * sy * cx + sz * cy * sx,
783 sz * cy * cx - cz * sy * sx,
784 cz * cy * cx + sz * sy * sx
796 static void rotatedlg_apply (GtkWidget *widget, RotateDialog* rotateDialog)
800 eulerXYZ[0] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->x));
801 gtk_spin_button_set_value(rotateDialog->x, 0.0f); // reset to 0 on Apply
803 eulerXYZ[1] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->y));
804 gtk_spin_button_set_value(rotateDialog->y, 0.0f);
806 eulerXYZ[2] = static_cast<float>(gtk_spin_button_get_value(rotateDialog->z));
807 gtk_spin_button_set_value(rotateDialog->z, 0.0f);
809 StringOutputStream command;
810 command << "rotateSelectedEulerXYZ -x " << eulerXYZ[0] << " -y " << eulerXYZ[1] << " -z " << eulerXYZ[2];
811 UndoableCommand undo(command.c_str());
813 GlobalSelectionSystem().rotateSelected(quaternion_for_euler_xyz_degrees(eulerXYZ));
819 RotateDialog rotateDialog;
821 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Arbitrary rotation", G_CALLBACK(dialog_delete_callback), &dialog);
823 GtkAccelGroup* accel = gtk_accel_group_new();
824 gtk_window_add_accel_group(window, accel);
827 GtkHBox* hbox = create_dialog_hbox(4, 4);
828 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
830 GtkTable* table = create_dialog_table(3, 2, 4, 4);
831 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
833 GtkWidget* label = gtk_label_new (" X ");
834 gtk_widget_show (label);
835 gtk_table_attach(table, label, 0, 1, 0, 1,
836 (GtkAttachOptions) (0),
837 (GtkAttachOptions) (0), 0, 0);
840 GtkWidget* label = gtk_label_new (" Y ");
841 gtk_widget_show (label);
842 gtk_table_attach(table, label, 0, 1, 1, 2,
843 (GtkAttachOptions) (0),
844 (GtkAttachOptions) (0), 0, 0);
847 GtkWidget* label = gtk_label_new (" Z ");
848 gtk_widget_show (label);
849 gtk_table_attach(table, label, 0, 1, 2, 3,
850 (GtkAttachOptions) (0),
851 (GtkAttachOptions) (0), 0, 0);
854 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
855 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
856 gtk_widget_show(GTK_WIDGET(spin));
857 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 0, 1,
858 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
859 (GtkAttachOptions) (0), 0, 0);
860 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
861 gtk_spin_button_set_wrap(spin, TRUE);
863 gtk_widget_grab_focus(GTK_WIDGET(spin));
865 rotateDialog.x = spin;
868 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
869 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
870 gtk_widget_show(GTK_WIDGET(spin));
871 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 1, 2,
872 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
873 (GtkAttachOptions) (0), 0, 0);
874 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
875 gtk_spin_button_set_wrap(spin, TRUE);
877 rotateDialog.y = spin;
880 GtkAdjustment* adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, -359, 359, 1, 10, 10));
881 GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(adj, 1, 0));
882 gtk_widget_show(GTK_WIDGET(spin));
883 gtk_table_attach(table, GTK_WIDGET(spin), 1, 2, 2, 3,
884 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
885 (GtkAttachOptions) (0), 0, 0);
886 gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
887 gtk_spin_button_set_wrap(spin, TRUE);
889 rotateDialog.z = spin;
893 GtkVBox* vbox = create_dialog_vbox(4);
894 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
896 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
897 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
898 widget_make_default(GTK_WIDGET(button));
899 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
902 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
903 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
904 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
907 GtkButton* button = create_dialog_button("Apply", G_CALLBACK(rotatedlg_apply), &rotateDialog);
908 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
913 if(modal_dialog_show(window, dialog) == eIDOK)
915 rotatedlg_apply(0, &rotateDialog);
918 gtk_widget_destroy(GTK_WIDGET(window));
928 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Scale", G_CALLBACK(dialog_delete_callback), &dialog);
930 GtkAccelGroup* accel = gtk_accel_group_new();
931 gtk_window_add_accel_group(window, accel);
934 GtkHBox* hbox = create_dialog_hbox(4, 4);
935 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
937 GtkTable* table = create_dialog_table(3, 2, 4, 4);
938 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
940 GtkWidget* label = gtk_label_new ("X:");
941 gtk_widget_show (label);
942 gtk_table_attach(table, label, 0, 1, 0, 1,
943 (GtkAttachOptions) (GTK_FILL),
944 (GtkAttachOptions) (0), 0, 0);
945 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
948 GtkWidget* label = gtk_label_new ("Y:");
949 gtk_widget_show (label);
950 gtk_table_attach(table, label, 0, 1, 1, 2,
951 (GtkAttachOptions) (GTK_FILL),
952 (GtkAttachOptions) (0), 0, 0);
953 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
956 GtkWidget* label = gtk_label_new ("Z:");
957 gtk_widget_show (label);
958 gtk_table_attach(table, label, 0, 1, 2, 3,
959 (GtkAttachOptions) (GTK_FILL),
960 (GtkAttachOptions) (0), 0, 0);
961 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
964 GtkWidget* entry = gtk_entry_new();
965 gtk_widget_show (entry);
966 gtk_table_attach(table, entry, 1, 2, 0, 1,
967 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
968 (GtkAttachOptions) (0), 0, 0);
970 gtk_widget_grab_focus(entry);
975 GtkWidget* entry = gtk_entry_new();
976 gtk_widget_show (entry);
977 gtk_table_attach(table, entry, 1, 2, 1, 2,
978 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
979 (GtkAttachOptions) (0), 0, 0);
984 GtkWidget* entry = gtk_entry_new();
985 gtk_widget_show (entry);
986 gtk_table_attach(table, entry, 1, 2, 2, 3,
987 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
988 (GtkAttachOptions) (0), 0, 0);
994 GtkVBox* vbox = create_dialog_vbox(4);
995 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
997 GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
998 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
999 widget_make_default(GTK_WIDGET(button));
1000 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
1003 GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
1004 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1005 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
1010 // Initialize dialog
1011 gtk_entry_set_text (GTK_ENTRY (x), "1.0");
1012 gtk_entry_set_text (GTK_ENTRY (y), "1.0");
1013 gtk_entry_set_text (GTK_ENTRY (z), "1.0");
1015 if(modal_dialog_show(window, dialog) == eIDOK)
1018 sx = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (x))));
1019 sy = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (y))));
1020 sz = static_cast<float>(atof(gtk_entry_get_text (GTK_ENTRY (z))));
1022 if (sx > 0 && sy > 0 && sz > 0)
1024 StringOutputStream command;
1025 command << "scaleSelected -x " << sx << " -y " << sy << " -z " << sz;
1026 UndoableCommand undo(command.c_str());
1028 Select_Scale(sx, sy, sz);
1032 globalOutputStream() << "Warning.. Tried to scale by a zero value.";
1036 gtk_widget_destroy(GTK_WIDGET(window));