also support XactCone and XactSphere
[divverent/netradiant.git] / radiant / patchmanip.cpp
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
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.
11
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.
16
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
20 */
21
22 #include "patchmanip.h"
23
24 #include "debugging/debugging.h"
25
26
27 #include "iselection.h"
28 #include "ipatch.h"
29
30 #include "math/vector.h"
31 #include "math/aabb.h"
32 #include "generic/callback.h"
33
34 #include "gtkutil/menu.h"
35 #include "gtkutil/image.h"
36 #include "map.h"
37 #include "mainframe.h"
38 #include "commands.h"
39 #include "gtkmisc.h"
40 #include "gtkdlgs.h"
41 #include "texwindow.h"
42 #include "xywindow.h"
43 #include "select.h"
44 #include "patch.h"
45 #include "grid.h"
46
47 PatchCreator* g_patchCreator = 0;
48
49 void Scene_PatchConstructPrefab(scene::Graph& graph, const AABB aabb, const char* shader, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3)
50 {
51   Select_Delete();
52   GlobalSelectionSystem().setSelectedAll(false);
53
54   NodeSmartReference node(g_patchCreator->createPatch());
55   Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(node);
56
57   Patch* patch = Node_getPatch(node);
58   patch->SetShader(shader);
59
60   patch->ConstructPrefab(aabb, eType, axis, width, height);
61   patch->controlPointsChanged();
62
63   {
64     scene::Path patchpath(makeReference(GlobalSceneGraph().root()));
65     patchpath.push(makeReference(*Map_GetWorldspawn(g_map)));
66     patchpath.push(makeReference(node.get()));
67     Instance_getSelectable(*graph.find(patchpath))->setSelected(true);
68   }
69 }
70
71
72 void Patch_makeCaps(Patch& patch, scene::Instance& instance, EPatchCap type, const char* shader)
73 {
74   if((type == eCapEndCap || type == eCapIEndCap)
75     && patch.getWidth() != 5)
76   {
77     globalErrorStream() << "cannot create end-cap - patch width != 5\n";
78     return;
79   }
80   if((type == eCapBevel || type == eCapIBevel)
81     && patch.getWidth() != 3 && patch.getWidth() != 5)
82   {
83     globalErrorStream() << "cannot create bevel-cap - patch width != 3\n";
84     return;
85   }
86   if(type == eCapCylinder
87     && patch.getWidth() != 9)
88   {
89     globalErrorStream() << "cannot create cylinder-cap - patch width != 9\n";
90     return;
91   }
92
93   {
94     NodeSmartReference cap(g_patchCreator->createPatch());
95     Node_getTraversable(instance.path().parent())->insert(cap);
96
97     patch.MakeCap(Node_getPatch(cap), type, ROW, true);
98     Node_getPatch(cap)->SetShader(shader);
99
100     scene::Path path(instance.path());
101     path.pop();
102     path.push(makeReference(cap.get()));
103     selectPath(path, true);
104   }
105
106   {
107     NodeSmartReference cap(g_patchCreator->createPatch());
108     Node_getTraversable(instance.path().parent())->insert(cap);
109
110     patch.MakeCap(Node_getPatch(cap), type, ROW, false);
111     Node_getPatch(cap)->SetShader(shader);
112
113     scene::Path path(instance.path());
114     path.pop();
115     path.push(makeReference(cap.get()));
116     selectPath(path, true);
117   }
118 }
119
120 typedef std::vector<scene::Instance*> InstanceVector;
121
122 class PatchStoreInstance
123 {
124   InstanceVector& m_instances;
125 public:
126   PatchStoreInstance(InstanceVector& instances) : m_instances(instances)
127   {
128   }
129   void operator()(PatchInstance& patch) const
130   {
131     m_instances.push_back(&patch);
132   }
133 };
134
135 enum ECapDialog {
136   PATCHCAP_BEVEL = 0,
137   PATCHCAP_ENDCAP,
138   PATCHCAP_INVERTED_BEVEL,
139   PATCHCAP_INVERTED_ENDCAP,
140   PATCHCAP_CYLINDER
141 };
142
143 EMessageBoxReturn DoCapDlg(ECapDialog *type);
144
145 void Scene_PatchDoCap_Selected(scene::Graph& graph, const char* shader)
146 {
147   ECapDialog nType;
148
149   if(DoCapDlg(&nType) == eIDOK)
150   {
151     EPatchCap eType;
152     switch(nType)
153     {
154     case PATCHCAP_INVERTED_BEVEL:
155       eType = eCapIBevel;
156       break;
157     case PATCHCAP_BEVEL:
158       eType = eCapBevel;
159       break;
160     case PATCHCAP_INVERTED_ENDCAP:
161       eType = eCapIEndCap;
162       break;
163     case PATCHCAP_ENDCAP:
164       eType = eCapEndCap;
165       break;
166     case PATCHCAP_CYLINDER:
167       eType = eCapCylinder;
168       break;
169     default:
170       ERROR_MESSAGE("invalid patch cap type");
171       return;
172     }
173   
174     InstanceVector instances;
175     Scene_forEachVisibleSelectedPatchInstance(PatchStoreInstance(instances));
176     for(InstanceVector::const_iterator i = instances.begin(); i != instances.end(); ++i)
177     {
178       Patch_makeCaps(* Node_getPatch((*i)->path().top()), *(*i), eType, shader);
179     }
180   }
181 }
182
183 Patch* Scene_GetUltimateSelectedVisiblePatch()
184 {
185   if(GlobalSelectionSystem().countSelected() != 0)
186   {
187     scene::Node& node = GlobalSelectionSystem().ultimateSelected().path().top();
188     if(node.visible())
189     {
190       return Node_getPatch(node);
191     }
192   }
193   return 0;
194 }
195
196
197 class PatchCapTexture
198 {
199 public:
200   void operator()(Patch& patch) const
201   {
202     patch.ProjectTexture(Patch::m_CycleCapIndex);
203   }
204 };
205
206 void Scene_PatchCapTexture_Selected(scene::Graph& graph)
207 {
208   Scene_forEachVisibleSelectedPatch(PatchCapTexture());
209   Patch::m_CycleCapIndex = (Patch::m_CycleCapIndex == 0) ? 1 : (Patch::m_CycleCapIndex == 1) ? 2 : 0;
210   SceneChangeNotify();
211 }
212
213 class PatchFlipTexture
214 {
215   int m_axis;
216 public:
217   PatchFlipTexture(int axis) : m_axis(axis)
218   {
219   }
220   void operator()(Patch& patch) const
221   {
222     patch.FlipTexture(m_axis);
223   }
224 };
225
226 void Scene_PatchFlipTexture_Selected(scene::Graph& graph, int axis)
227 {
228   Scene_forEachVisibleSelectedPatch(PatchFlipTexture(axis));
229 }
230
231 class PatchNaturalTexture
232 {
233 public:
234   void operator()(Patch& patch) const
235   {
236     patch.NaturalTexture();
237   }
238 };
239
240 void Scene_PatchNaturalTexture_Selected(scene::Graph& graph)
241 {
242   Scene_forEachVisibleSelectedPatch(PatchNaturalTexture());
243   SceneChangeNotify();
244 }
245
246
247 class PatchInsertRemove
248 {
249   bool m_insert, m_column, m_first;
250 public:
251   PatchInsertRemove(bool insert, bool column, bool first) : m_insert(insert), m_column(column), m_first(first)
252   {
253   }
254   void operator()(Patch& patch) const
255   {
256     patch.InsertRemove(m_insert, m_column, m_first);
257   }
258 };
259
260 void Scene_PatchInsertRemove_Selected(scene::Graph& graph, bool bInsert, bool bColumn, bool bFirst)
261 {
262   Scene_forEachVisibleSelectedPatch(PatchInsertRemove(bInsert, bColumn, bFirst));
263 }
264
265 class PatchInvertMatrix
266 {
267 public:
268   void operator()(Patch& patch) const
269   {
270     patch.InvertMatrix();
271   }
272 };
273
274 void Scene_PatchInvert_Selected(scene::Graph& graph)
275 {
276   Scene_forEachVisibleSelectedPatch(PatchInvertMatrix());
277 }
278
279 class PatchRedisperse
280 {
281   EMatrixMajor m_major;
282 public:
283   PatchRedisperse(EMatrixMajor major) : m_major(major)
284   {
285   }
286   void operator()(Patch& patch) const
287   {
288     patch.Redisperse(m_major);
289   }
290 };
291
292 void Scene_PatchRedisperse_Selected(scene::Graph& graph, EMatrixMajor major)
293 {
294   Scene_forEachVisibleSelectedPatch(PatchRedisperse(major));
295 }
296
297 class PatchSmooth
298 {
299   EMatrixMajor m_major;
300 public:
301   PatchSmooth(EMatrixMajor major) : m_major(major)
302   {
303   }
304   void operator()(Patch& patch) const
305   {
306     patch.Smooth(m_major);
307   }
308 };
309
310 void Scene_PatchSmooth_Selected(scene::Graph& graph, EMatrixMajor major)
311 {
312   Scene_forEachVisibleSelectedPatch(PatchSmooth(major));
313 }
314
315 class PatchTransposeMatrix
316 {
317 public:
318   void operator()(Patch& patch) const
319   {
320     patch.TransposeMatrix();
321   }
322 };
323
324 void Scene_PatchTranspose_Selected(scene::Graph& graph)
325 {
326   Scene_forEachVisibleSelectedPatch(PatchTransposeMatrix());
327 }
328
329 class PatchSetShader
330 {
331   const char* m_name;
332 public:
333   PatchSetShader(const char* name)
334     : m_name(name)
335   {
336   }
337   void operator()(Patch& patch) const
338   {
339     patch.SetShader(m_name);
340   }
341 };
342
343 void Scene_PatchSetShader_Selected(scene::Graph& graph, const char* name)
344 {
345   Scene_forEachVisibleSelectedPatch(PatchSetShader(name));
346   SceneChangeNotify();
347 }
348
349 void Scene_PatchGetShader_Selected(scene::Graph& graph, CopiedString& name)
350 {
351   Patch* patch = Scene_GetUltimateSelectedVisiblePatch();
352   if(patch != 0)
353   {
354     name = patch->GetShader();
355   }
356 }
357
358 class PatchSelectByShader
359 {
360   const char* m_name;
361 public:
362   inline PatchSelectByShader(const char* name)
363     : m_name(name)
364   {
365   }
366   void operator()(PatchInstance& patch) const
367   {
368     if(shader_equal(patch.getPatch().GetShader(), m_name))
369     {
370       patch.setSelected(true);
371     }
372   }
373 };
374
375 void Scene_PatchSelectByShader(scene::Graph& graph, const char* name)
376 {
377   Scene_forEachVisiblePatchInstance(PatchSelectByShader(name));
378 }
379
380
381 class PatchFindReplaceShader
382 {
383   const char* m_find;
384   const char* m_replace;
385 public:
386   PatchFindReplaceShader(const char* find, const char* replace) : m_find(find), m_replace(replace)
387   {
388   }
389   void operator()(Patch& patch) const
390   {
391     if(shader_equal(patch.GetShader(), m_find))
392     {
393       patch.SetShader(m_replace);
394     }
395   }
396 };
397
398 void Scene_PatchFindReplaceShader(scene::Graph& graph, const char* find, const char* replace)
399 {
400   Scene_forEachVisiblePatch(PatchFindReplaceShader(find, replace));
401 }
402
403 void Scene_PatchFindReplaceShader_Selected(scene::Graph& graph, const char* find, const char* replace)
404 {
405   Scene_forEachVisibleSelectedPatch(PatchFindReplaceShader(find, replace));
406 }
407
408
409 AABB PatchCreator_getBounds()
410 {
411   AABB aabb(aabb_for_minmax(Select_getWorkZone().d_work_min, Select_getWorkZone().d_work_max));
412
413   float gridSize = GetGridSize();
414
415   if(aabb.extents[0] == 0)
416   {
417     aabb.extents[0] = gridSize;
418   }
419   if(aabb.extents[1] == 0)
420   {
421     aabb.extents[1] = gridSize;
422   }
423   if(aabb.extents[2] == 0)
424   {
425     aabb.extents[2] = gridSize;
426   }
427
428   if(aabb_valid(aabb))
429   {
430     return aabb;
431   }
432   return AABB(Vector3(0, 0, 0), Vector3(64, 64, 64));
433 }
434
435 void Patch_XactCylinder()
436 {
437   UndoableCommand undo("patchCreateXactCylinder");
438
439   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eXactCylinder, GlobalXYWnd_getCurrentViewType());
440 }
441
442 void Patch_XactSphere()
443 {
444   UndoableCommand undo("patchCreateXactSphere");
445
446   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eXactSphere, GlobalXYWnd_getCurrentViewType());
447 }
448
449 void Patch_XactCone()
450 {
451   UndoableCommand undo("patchCreateXactCone");
452
453   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eXactCone, GlobalXYWnd_getCurrentViewType());
454 }
455
456 void Patch_Cylinder()
457 {
458   UndoableCommand undo("patchCreateCylinder");
459
460   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eCylinder, GlobalXYWnd_getCurrentViewType());
461 }
462
463 void Patch_DenseCylinder()
464 {
465   UndoableCommand undo("patchCreateDenseCylinder");
466
467   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eDenseCylinder, GlobalXYWnd_getCurrentViewType());
468 }
469
470 void Patch_VeryDenseCylinder()
471 {
472   UndoableCommand undo("patchCreateVeryDenseCylinder");
473
474   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eVeryDenseCylinder, GlobalXYWnd_getCurrentViewType());
475 }
476
477 void Patch_SquareCylinder()
478 {
479   UndoableCommand undo("patchCreateSquareCylinder");
480
481   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eSqCylinder, GlobalXYWnd_getCurrentViewType());
482 }
483
484 void Patch_Endcap()
485 {
486   UndoableCommand undo("patchCreateCaps");
487
488   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eEndCap, GlobalXYWnd_getCurrentViewType());
489 }
490
491 void Patch_Bevel()
492 {
493   UndoableCommand undo("patchCreateBevel");
494
495   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eBevel, GlobalXYWnd_getCurrentViewType());
496 }
497
498 void Patch_Sphere()
499 {
500   UndoableCommand undo("patchCreateSphere");
501
502   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eSphere, GlobalXYWnd_getCurrentViewType());
503 }
504
505 void Patch_SquareBevel()
506 {
507 }
508
509 void Patch_SquareEndcap()
510 {
511 }
512
513 void Patch_Cone()
514 {
515   UndoableCommand undo("patchCreateCone");
516
517   Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eCone, GlobalXYWnd_getCurrentViewType());
518 }
519
520 void DoNewPatchDlg();
521
522 void Patch_Plane()
523 {
524   UndoableCommand undo("patchCreatePlane");
525
526   DoNewPatchDlg();
527 }
528
529 void Patch_InsertInsertColumn()
530 {
531   UndoableCommand undo("patchInsertColumns");
532
533   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), true, true, false);
534 }
535
536 void Patch_InsertAddColumn()
537 {
538   UndoableCommand undo("patchAddColumns");
539
540   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), true, true, true);
541 }
542
543 void Patch_InsertInsertRow()
544 {
545   UndoableCommand undo("patchInsertRows");
546
547   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), true, false, false);
548 }
549
550 void Patch_InsertAddRow()
551 {
552   UndoableCommand undo("patchAddRows");
553
554   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), true, false, true);
555 }
556
557 void Patch_DeleteFirstColumn()
558 {
559   UndoableCommand undo("patchDeleteFirstColumns");
560
561   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), false, true, true);
562 }
563
564 void Patch_DeleteLastColumn()
565 {
566   UndoableCommand undo("patchDeleteLastColumns");
567
568   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), false, true, false);
569 }
570
571 void Patch_DeleteFirstRow()
572 {
573   UndoableCommand undo("patchDeleteFirstRows");
574
575   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), false, false, true);
576 }
577
578 void Patch_DeleteLastRow()
579 {
580   UndoableCommand undo("patchDeleteLastRows");
581
582   Scene_PatchInsertRemove_Selected(GlobalSceneGraph(), false, false, false);
583 }
584
585 void Patch_Invert()
586 {
587   UndoableCommand undo("patchInvert");
588
589   Scene_PatchInvert_Selected(GlobalSceneGraph());
590 }
591
592 void Patch_RedisperseRows()
593 {
594   UndoableCommand undo("patchRedisperseRows");
595
596   Scene_PatchRedisperse_Selected(GlobalSceneGraph(), ROW);
597 }
598
599 void Patch_RedisperseCols()
600 {
601   UndoableCommand undo("patchRedisperseColumns");
602
603   Scene_PatchRedisperse_Selected(GlobalSceneGraph(), COL);
604 }
605
606 void Patch_SmoothRows()
607 {
608   UndoableCommand undo("patchSmoothRows");
609
610   Scene_PatchSmooth_Selected(GlobalSceneGraph(), ROW);
611 }
612
613 void Patch_SmoothCols()
614 {
615   UndoableCommand undo("patchSmoothColumns");
616
617   Scene_PatchSmooth_Selected(GlobalSceneGraph(), COL);
618 }
619
620 void Patch_Transpose()
621 {
622   UndoableCommand undo("patchTranspose");
623
624   Scene_PatchTranspose_Selected(GlobalSceneGraph());
625 }
626
627 void Patch_Cap()
628 {
629   // FIXME: add support for patch cap creation
630   // Patch_CapCurrent();
631   UndoableCommand undo("patchCreateCaps");
632
633   Scene_PatchDoCap_Selected(GlobalSceneGraph(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()));
634 }
635
636 void Patch_CycleProjection()
637 {
638   UndoableCommand undo("patchCycleUVProjectionAxis");
639
640   Scene_PatchCapTexture_Selected(GlobalSceneGraph());
641 }
642
643 ///\todo Unfinished.
644 void Patch_OverlayOn()
645 {
646 }
647
648 ///\todo Unfinished.
649 void Patch_OverlayOff()
650 {
651 }
652
653 void Patch_FlipTextureX()
654 {
655   UndoableCommand undo("patchFlipTextureU");
656
657   Scene_PatchFlipTexture_Selected(GlobalSceneGraph(), 0);
658 }
659
660 void Patch_FlipTextureY()
661 {
662   UndoableCommand undo("patchFlipTextureV");
663
664   Scene_PatchFlipTexture_Selected(GlobalSceneGraph(), 1);
665 }
666
667 void Patch_NaturalTexture()
668 {
669   UndoableCommand undo("patchNaturalTexture");
670
671   Scene_PatchNaturalTexture_Selected(GlobalSceneGraph());
672 }
673
674
675
676
677 #include "ifilter.h"
678
679
680 class filter_patch_all : public PatchFilter
681 {
682 public:
683   bool filter(const Patch& patch) const
684   {
685     return true;
686   }
687 };
688
689 class filter_patch_shader : public PatchFilter
690 {
691   const char* m_shader;
692 public:
693   filter_patch_shader(const char* shader) : m_shader(shader)
694   {
695   }
696   bool filter(const Patch& patch) const
697   {
698     return shader_equal(patch.GetShader(), m_shader);
699   }
700 };
701
702 class filter_patch_flags : public PatchFilter
703 {
704   int m_flags;
705 public:
706   filter_patch_flags(int flags) : m_flags(flags)
707   {
708   }
709   bool filter(const Patch& patch) const
710   {
711     return (patch.getShaderFlags() & m_flags) != 0;
712   }
713 };
714
715
716 filter_patch_all g_filter_patch_all;
717 filter_patch_shader g_filter_patch_clip("textures/common/clip");
718 filter_patch_shader g_filter_patch_weapclip("textures/common/weapclip");
719 filter_patch_flags g_filter_patch_translucent(QER_TRANS);
720
721 void PatchFilters_construct()
722 {
723   add_patch_filter(g_filter_patch_all, EXCLUDE_CURVES);
724   add_patch_filter(g_filter_patch_clip, EXCLUDE_CLIP);
725   add_patch_filter(g_filter_patch_weapclip, EXCLUDE_CLIP);
726   add_patch_filter(g_filter_patch_translucent, EXCLUDE_TRANSLUCENT);
727 }
728
729
730 #include "preferences.h"
731
732 void Patch_constructPreferences(PreferencesPage& page)
733 {
734   page.appendEntry("Patch Subdivide Threshold", g_PatchSubdivideThreshold);
735 }
736 void Patch_constructPage(PreferenceGroup& group)
737 {
738   PreferencesPage page(group.createPage("Patches", "Patch Display Preferences"));
739   Patch_constructPreferences(page);
740 }
741 void Patch_registerPreferencesPage()
742 {
743   PreferencesDialog_addDisplayPage(FreeCaller1<PreferenceGroup&, Patch_constructPage>());
744 }
745
746
747 #include "preferencesystem.h"
748
749 void PatchPreferences_construct()
750 {
751   GlobalPreferenceSystem().registerPreference("Subdivisions", IntImportStringCaller(g_PatchSubdivideThreshold), IntExportStringCaller(g_PatchSubdivideThreshold));
752 }
753
754
755 #include "generic/callback.h"
756
757 void Patch_registerCommands()
758 {
759   GlobalCommands_insert("InvertCurveTextureX", FreeCaller<Patch_FlipTextureX>(), Accelerator('I', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
760   GlobalCommands_insert("InvertCurveTextureY", FreeCaller<Patch_FlipTextureY>(), Accelerator('I', (GdkModifierType)GDK_SHIFT_MASK));
761   GlobalCommands_insert("IncPatchColumn", FreeCaller<Patch_InsertInsertColumn>(), Accelerator(GDK_KP_Add, (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
762   GlobalCommands_insert("IncPatchRow", FreeCaller<Patch_InsertInsertRow>(), Accelerator(GDK_KP_Add, (GdkModifierType)GDK_CONTROL_MASK));
763   GlobalCommands_insert("DecPatchColumn", FreeCaller<Patch_DeleteLastColumn>(), Accelerator(GDK_KP_Subtract, (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
764   GlobalCommands_insert("DecPatchRow", FreeCaller<Patch_DeleteLastRow>(), Accelerator(GDK_KP_Subtract, (GdkModifierType)GDK_CONTROL_MASK));
765   GlobalCommands_insert("NaturalizePatch", FreeCaller<Patch_NaturalTexture>(), Accelerator('N', (GdkModifierType)GDK_CONTROL_MASK));
766   GlobalCommands_insert("PatchCylinder", FreeCaller<Patch_Cylinder>());
767   GlobalCommands_insert("PatchDenseCylinder", FreeCaller<Patch_DenseCylinder>());
768   GlobalCommands_insert("PatchVeryDenseCylinder", FreeCaller<Patch_VeryDenseCylinder>());
769   GlobalCommands_insert("PatchSquareCylinder", FreeCaller<Patch_SquareCylinder>());
770   GlobalCommands_insert("PatchXactCylinder", FreeCaller<Patch_XactCylinder>());
771   GlobalCommands_insert("PatchXactSphere", FreeCaller<Patch_XactSphere>());
772   GlobalCommands_insert("PatchXactCone", FreeCaller<Patch_XactCone>());
773   GlobalCommands_insert("PatchEndCap", FreeCaller<Patch_Endcap>());
774   GlobalCommands_insert("PatchBevel", FreeCaller<Patch_Bevel>());
775   GlobalCommands_insert("PatchSquareBevel", FreeCaller<Patch_SquareBevel>());
776   GlobalCommands_insert("PatchSquareEndcap", FreeCaller<Patch_SquareEndcap>());
777   GlobalCommands_insert("PatchCone", FreeCaller<Patch_Cone>());
778   GlobalCommands_insert("PatchSphere", FreeCaller<Patch_Sphere>());
779   GlobalCommands_insert("SimplePatchMesh", FreeCaller<Patch_Plane>(), Accelerator('P', (GdkModifierType)GDK_SHIFT_MASK));
780   GlobalCommands_insert("PatchInsertInsertColumn", FreeCaller<Patch_InsertInsertColumn>());
781   GlobalCommands_insert("PatchInsertAddColumn", FreeCaller<Patch_InsertAddColumn>());
782   GlobalCommands_insert("PatchInsertInsertRow", FreeCaller<Patch_InsertInsertRow>());
783   GlobalCommands_insert("PatchInsertAddRow", FreeCaller<Patch_InsertAddRow>());
784   GlobalCommands_insert("PatchDeleteFirstColumn", FreeCaller<Patch_DeleteFirstColumn>());
785   GlobalCommands_insert("PatchDeleteLastColumn", FreeCaller<Patch_DeleteLastColumn>());
786   GlobalCommands_insert("PatchDeleteFirstRow", FreeCaller<Patch_DeleteFirstRow>());
787   GlobalCommands_insert("PatchDeleteLastRow", FreeCaller<Patch_DeleteLastRow>());
788   GlobalCommands_insert("InvertCurve", FreeCaller<Patch_Invert>(), Accelerator('I', (GdkModifierType)GDK_CONTROL_MASK));
789   GlobalCommands_insert("RedisperseRows", FreeCaller<Patch_RedisperseRows>(), Accelerator('E', (GdkModifierType)GDK_CONTROL_MASK));
790   GlobalCommands_insert("RedisperseCols", FreeCaller<Patch_RedisperseCols>(), Accelerator('E', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
791   GlobalCommands_insert("SmoothRows", FreeCaller<Patch_SmoothRows>(), Accelerator('W', (GdkModifierType)GDK_CONTROL_MASK));
792   GlobalCommands_insert("SmoothCols", FreeCaller<Patch_SmoothCols>(), Accelerator('W', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
793   GlobalCommands_insert("MatrixTranspose", FreeCaller<Patch_Transpose>(), Accelerator('M', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
794   GlobalCommands_insert("CapCurrentCurve", FreeCaller<Patch_Cap>(), Accelerator('C', (GdkModifierType)GDK_SHIFT_MASK));
795   GlobalCommands_insert("CycleCapTexturePatch", FreeCaller<Patch_CycleProjection>(), Accelerator('N', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
796   GlobalCommands_insert("MakeOverlayPatch", FreeCaller<Patch_OverlayOn>(), Accelerator('Y'));
797   GlobalCommands_insert("ClearPatchOverlays", FreeCaller<Patch_OverlayOff>(), Accelerator('L', (GdkModifierType)GDK_CONTROL_MASK));
798 }
799
800 void Patch_constructToolbar(GtkToolbar* toolbar)
801 {
802   toolbar_append_button(toolbar, "Put caps on the current patch (SHIFT + C)", "curve_cap.bmp", "CapCurrentCurve");
803 }
804
805 void Patch_constructMenu(GtkMenu* menu)
806 {
807   create_menu_item_with_mnemonic(menu, "Cylinder", "PatchCylinder");
808   {
809     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "More Cylinders");
810     if (g_Layout_enableDetachableMenus.m_value)
811       menu_tearoff (menu_in_menu);
812     create_menu_item_with_mnemonic(menu_in_menu, "Dense Cylinder", "PatchDenseCylinder");
813     create_menu_item_with_mnemonic(menu_in_menu, "Very Dense Cylinder", "PatchVeryDenseCylinder");
814     create_menu_item_with_mnemonic(menu_in_menu, "Square Cylinder", "PatchSquareCylinder");
815     create_menu_item_with_mnemonic(menu_in_menu, "Exact Cylinder...", "PatchXactCylinder");
816   }
817   menu_separator (menu);
818   create_menu_item_with_mnemonic(menu, "End cap", "PatchEndCap");
819   create_menu_item_with_mnemonic(menu, "Bevel", "PatchBevel");
820   {
821     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "More End caps, Bevels");
822     if (g_Layout_enableDetachableMenus.m_value)
823       menu_tearoff (menu_in_menu);
824     create_menu_item_with_mnemonic(menu_in_menu, "Square Endcap", "PatchSquareBevel");
825     create_menu_item_with_mnemonic(menu_in_menu, "Square Bevel", "PatchSquareEndcap");
826   }
827   menu_separator (menu);
828   create_menu_item_with_mnemonic(menu, "Cone", "PatchCone");
829   create_menu_item_with_mnemonic(menu, "Exact Cone...", "PatchXactCone");
830   menu_separator (menu);
831   create_menu_item_with_mnemonic(menu, "Sphere", "PatchSphere");
832   create_menu_item_with_mnemonic(menu, "Exact Sphere...", "PatchXactSphere");
833   menu_separator (menu);
834   create_menu_item_with_mnemonic(menu, "Simple Patch Mesh...", "SimplePatchMesh");
835   menu_separator (menu);
836   {
837     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Insert");
838     if (g_Layout_enableDetachableMenus.m_value)
839       menu_tearoff (menu_in_menu);
840     create_menu_item_with_mnemonic(menu_in_menu, "Insert (2) Columns", "PatchInsertInsertColumn");
841     create_menu_item_with_mnemonic(menu_in_menu, "Add (2) Columns", "PatchInsertAddColumn");
842     menu_separator (menu_in_menu);
843     create_menu_item_with_mnemonic(menu_in_menu, "Insert (2) Rows", "PatchInsertInsertRow");
844     create_menu_item_with_mnemonic(menu_in_menu, "Add (2) Rows", "PatchInsertAddRow");
845   }
846   {
847     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Delete");
848     if (g_Layout_enableDetachableMenus.m_value)
849       menu_tearoff (menu_in_menu);
850     create_menu_item_with_mnemonic(menu_in_menu, "First (2) Columns", "PatchDeleteFirstColumn");
851     create_menu_item_with_mnemonic(menu_in_menu, "Last (2) Columns", "PatchDeleteLastColumn");
852     menu_separator (menu_in_menu);
853     create_menu_item_with_mnemonic(menu_in_menu, "First (2) Rows", "PatchDeleteFirstRow");
854     create_menu_item_with_mnemonic(menu_in_menu, "Last (2) Rows", "PatchDeleteLastRow");
855   }
856   menu_separator (menu);
857   {
858     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Matrix");
859     if (g_Layout_enableDetachableMenus.m_value)
860       menu_tearoff (menu_in_menu);
861     create_menu_item_with_mnemonic(menu_in_menu, "Invert", "InvertCurve");
862     GtkMenu* menu_3 = create_sub_menu_with_mnemonic (menu_in_menu, "Re-disperse");
863     if (g_Layout_enableDetachableMenus.m_value)
864       menu_tearoff (menu_3);
865     create_menu_item_with_mnemonic(menu_3, "Rows", "RedisperseRows");
866     create_menu_item_with_mnemonic(menu_3, "Columns", "RedisperseCols");
867     GtkMenu* menu_4 = create_sub_menu_with_mnemonic (menu_in_menu, "Smooth");
868     if (g_Layout_enableDetachableMenus.m_value)
869       menu_tearoff (menu_4);
870     create_menu_item_with_mnemonic(menu_4, "Rows", "SmoothRows");
871     create_menu_item_with_mnemonic(menu_4, "Columns", "SmoothCols");
872     create_menu_item_with_mnemonic(menu_in_menu, "Transpose", "MatrixTranspose");
873   }
874   menu_separator (menu);
875   create_menu_item_with_mnemonic(menu, "Cap Selection", "CapCurrentCurve");
876   create_menu_item_with_mnemonic(menu, "Cycle Cap Texture", "CycleCapTexturePatch");
877   menu_separator (menu);
878   {
879     GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic (menu, "Overlay");
880     if (g_Layout_enableDetachableMenus.m_value)
881       menu_tearoff (menu_in_menu);
882     create_menu_item_with_mnemonic(menu_in_menu, "Set", "MakeOverlayPatch");
883     create_menu_item_with_mnemonic(menu_in_menu, "Clear", "ClearPatchOverlays");
884   }
885 }
886
887
888 #include <gtk/gtkbox.h>
889 #include <gtk/gtktable.h>
890 #include <gtk/gtktogglebutton.h>
891 #include <gtk/gtkradiobutton.h>
892 #include <gtk/gtkcombobox.h>
893 #include <gtk/gtklabel.h>
894 #include "gtkutil/dialog.h"
895 #include "gtkutil/widget.h"
896
897 void DoNewPatchDlg()
898 {
899   ModalDialog dialog;
900   GtkComboBox* width;
901   GtkComboBox* height;
902
903   GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Patch density", G_CALLBACK(dialog_delete_callback), &dialog);
904
905   GtkAccelGroup* accel = gtk_accel_group_new();
906   gtk_window_add_accel_group(window, accel);
907
908   {
909     GtkHBox* hbox = create_dialog_hbox(4, 4);
910     gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
911     {
912       GtkTable* table = create_dialog_table(2, 2, 4, 4);
913       gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
914       {
915         GtkLabel* label = GTK_LABEL(gtk_label_new("Width:"));
916         gtk_widget_show(GTK_WIDGET(label));
917         gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 0, 1,
918                           (GtkAttachOptions) (GTK_FILL),
919                           (GtkAttachOptions) (0), 0, 0);
920         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
921       }
922       {
923         GtkLabel* label = GTK_LABEL(gtk_label_new("Height:"));
924         gtk_widget_show(GTK_WIDGET(label));
925         gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 1, 2,
926                           (GtkAttachOptions) (GTK_FILL),
927                           (GtkAttachOptions) (0), 0, 0);
928         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
929       }
930
931       {
932         GtkComboBox* combo = GTK_COMBO_BOX(gtk_combo_box_new_text());
933         gtk_combo_box_append_text(combo, "3");
934         gtk_combo_box_append_text(combo, "5");
935         gtk_combo_box_append_text(combo, "7");
936         gtk_combo_box_append_text(combo, "9");
937         gtk_combo_box_append_text(combo, "11");
938         gtk_combo_box_append_text(combo, "13");
939         gtk_combo_box_append_text(combo, "15");
940         gtk_combo_box_append_text(combo, "17");
941         gtk_combo_box_append_text(combo, "19");
942         gtk_combo_box_append_text(combo, "21");
943         gtk_combo_box_append_text(combo, "23");
944         gtk_combo_box_append_text(combo, "25");
945         gtk_combo_box_append_text(combo, "27");
946         gtk_combo_box_append_text(combo, "29");
947         gtk_combo_box_append_text(combo, "31"); // MAX_PATCH_SIZE is 32, so we should be able to do 31...
948         gtk_widget_show(GTK_WIDGET(combo));
949         gtk_table_attach(table, GTK_WIDGET(combo), 1, 2, 0, 1,
950                           (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
951                           (GtkAttachOptions) (0), 0, 0);
952
953         width = combo;
954       }
955       {
956         GtkComboBox* combo = GTK_COMBO_BOX(gtk_combo_box_new_text());
957         gtk_combo_box_append_text(combo, "3");
958         gtk_combo_box_append_text(combo, "5");
959         gtk_combo_box_append_text(combo, "7");
960         gtk_combo_box_append_text(combo, "9");
961         gtk_combo_box_append_text(combo, "11");
962         gtk_combo_box_append_text(combo, "13");
963         gtk_combo_box_append_text(combo, "15");
964         gtk_combo_box_append_text(combo, "17");
965         gtk_combo_box_append_text(combo, "19");
966         gtk_combo_box_append_text(combo, "21");
967         gtk_combo_box_append_text(combo, "23");
968         gtk_combo_box_append_text(combo, "25");
969         gtk_combo_box_append_text(combo, "27");
970         gtk_combo_box_append_text(combo, "29");
971         gtk_combo_box_append_text(combo, "31"); // MAX_PATCH_SIZE is 32, so we should be able to do 31...
972         gtk_widget_show(GTK_WIDGET(combo));
973         gtk_table_attach(table, GTK_WIDGET(combo), 1, 2, 1, 2,
974                           (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
975                           (GtkAttachOptions) (0), 0, 0);
976
977         height = combo;
978       }
979     }
980
981     {
982       GtkVBox* vbox = create_dialog_vbox(4);
983       gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
984       {
985         GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &dialog);
986         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
987         widget_make_default(GTK_WIDGET(button));
988         gtk_widget_grab_focus(GTK_WIDGET(button));
989         gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
990       }
991       {
992         GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &dialog);
993         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
994         gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
995       }
996     }
997   }
998
999   // Initialize dialog
1000   gtk_combo_box_set_active(width, 0);
1001   gtk_combo_box_set_active(height, 0);
1002
1003   if(modal_dialog_show(window, dialog) == eIDOK)
1004   {
1005     int w = gtk_combo_box_get_active(width) * 2 + 3;
1006     int h = gtk_combo_box_get_active(height) * 2 + 3;
1007
1008     Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), ePlane, GlobalXYWnd_getCurrentViewType(), w, h);
1009   }
1010
1011   gtk_widget_destroy(GTK_WIDGET(window));
1012 }
1013
1014
1015
1016
1017 EMessageBoxReturn DoCapDlg(ECapDialog* type)
1018 {
1019   ModalDialog dialog;
1020   ModalDialogButton ok_button(dialog, eIDOK);
1021   ModalDialogButton cancel_button(dialog, eIDCANCEL);
1022   GtkWidget* bevel;
1023   GtkWidget* ibevel;
1024   GtkWidget* endcap;
1025   GtkWidget* iendcap;
1026   GtkWidget* cylinder;
1027  
1028   GtkWindow* window = create_modal_dialog_window(MainFrame_getWindow(), "Cap", dialog);
1029
1030   GtkAccelGroup *accel_group = gtk_accel_group_new();
1031   gtk_window_add_accel_group(window, accel_group);
1032
1033   {
1034     GtkHBox* hbox = create_dialog_hbox(4, 4);
1035     gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
1036
1037     {
1038       // Gef: Added a vbox to contain the toggle buttons
1039       GtkVBox* radio_vbox = create_dialog_vbox(4);
1040       gtk_container_add(GTK_CONTAINER(hbox), GTK_WIDGET(radio_vbox));
1041       
1042       {
1043         GtkTable* table = GTK_TABLE(gtk_table_new(5, 2, FALSE));
1044         gtk_widget_show(GTK_WIDGET(table));
1045         gtk_box_pack_start(GTK_BOX(radio_vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
1046         gtk_table_set_row_spacings(table, 5);
1047         gtk_table_set_col_spacings(table, 5);
1048  
1049         {
1050           GtkImage* image = new_local_image("cap_bevel.bmp");
1051           gtk_widget_show(GTK_WIDGET(image));
1052           gtk_table_attach(table, GTK_WIDGET(image), 0, 1, 0, 1,
1053                             (GtkAttachOptions) (GTK_FILL),
1054                             (GtkAttachOptions) (0), 0, 0);
1055         }
1056         {
1057           GtkImage* image = new_local_image("cap_endcap.bmp");
1058           gtk_widget_show(GTK_WIDGET(image));
1059           gtk_table_attach(table, GTK_WIDGET(image), 0, 1, 1, 2,
1060                             (GtkAttachOptions) (GTK_FILL),
1061                             (GtkAttachOptions) (0), 0, 0);
1062         }
1063         {
1064           GtkImage* image = new_local_image("cap_ibevel.bmp");
1065           gtk_widget_show(GTK_WIDGET(image));
1066           gtk_table_attach(table, GTK_WIDGET(image), 0, 1, 2, 3,
1067                             (GtkAttachOptions) (GTK_FILL),
1068                             (GtkAttachOptions) (0), 0, 0);
1069         }
1070         {
1071           GtkImage* image = new_local_image("cap_iendcap.bmp");
1072           gtk_widget_show(GTK_WIDGET(image));
1073           gtk_table_attach(table, GTK_WIDGET(image), 0, 1, 3, 4,
1074                             (GtkAttachOptions) (GTK_FILL),
1075                             (GtkAttachOptions) (0), 0, 0);
1076         }
1077         {
1078           GtkImage* image = new_local_image("cap_cylinder.bmp");
1079           gtk_widget_show(GTK_WIDGET(image));
1080           gtk_table_attach(table, GTK_WIDGET(image), 0, 1, 4, 5,
1081                             (GtkAttachOptions) (GTK_FILL),
1082                             (GtkAttachOptions) (0), 0, 0);
1083         }
1084
1085         GSList* group = 0;
1086         {
1087           GtkWidget* button = gtk_radio_button_new_with_label (group, "Bevel");
1088           gtk_widget_show (button);
1089           gtk_table_attach(table, button, 1, 2, 0, 1,
1090                             (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
1091                             (GtkAttachOptions) (0), 0, 0);
1092           group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1093
1094           bevel = button;
1095         }
1096         {
1097           GtkWidget* button = gtk_radio_button_new_with_label (group, "Endcap");
1098           gtk_widget_show (button);
1099           gtk_table_attach(table, button, 1, 2, 1, 2,
1100                             (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
1101                             (GtkAttachOptions) (0), 0, 0);
1102           group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1103
1104           endcap = button;
1105         }
1106         {
1107           GtkWidget* button = gtk_radio_button_new_with_label (group, "Inverted Bevel");
1108           gtk_widget_show (button);
1109           gtk_table_attach(table, button, 1, 2, 2, 3,
1110                             (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
1111                             (GtkAttachOptions) (0), 0, 0);
1112           group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1113
1114           ibevel = button;
1115         }
1116         {
1117           GtkWidget* button = gtk_radio_button_new_with_label (group, "Inverted Endcap");
1118           gtk_widget_show (button);
1119           gtk_table_attach(table, button, 1, 2, 3, 4,
1120                             (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
1121                             (GtkAttachOptions) (0), 0, 0);
1122           group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1123
1124           iendcap = button;
1125         }
1126         {
1127           GtkWidget* button = gtk_radio_button_new_with_label (group, "Cylinder");
1128           gtk_widget_show (button);
1129           gtk_table_attach(table, button, 1, 2, 4, 5,
1130                             (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
1131                             (GtkAttachOptions) (0), 0, 0);
1132           group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1133
1134           cylinder = button;
1135         }
1136       }
1137     }
1138     
1139     {
1140       GtkVBox* vbox = create_dialog_vbox(4);
1141       gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 0);
1142       {
1143         GtkButton* button = create_modal_dialog_button("OK", ok_button);
1144         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1145         widget_make_default(GTK_WIDGET(button));
1146         gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel_group, GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE);
1147       }
1148       {
1149         GtkButton* button = create_modal_dialog_button("Cancel", cancel_button);
1150         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
1151         gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel_group, GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE);
1152       }
1153     }
1154   }
1155
1156   // Initialize dialog
1157   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bevel), TRUE);
1158   
1159   EMessageBoxReturn ret = modal_dialog_show(window, dialog);
1160   if (ret == eIDOK)
1161   {
1162     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bevel)))
1163       *type = PATCHCAP_BEVEL;
1164     else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(endcap)))
1165       *type = PATCHCAP_ENDCAP;
1166     else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ibevel)))
1167       *type = PATCHCAP_INVERTED_BEVEL;
1168     else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(iendcap)))
1169       *type = PATCHCAP_INVERTED_ENDCAP;
1170     else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cylinder)))
1171       *type = PATCHCAP_CYLINDER;
1172   }
1173
1174   gtk_widget_destroy(GTK_WIDGET(window));
1175
1176   return ret;
1177 }