]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/patchdialog.cpp
* reactivated WXY_Print function to generate screenshots from the xy window
[xonotic/netradiant.git] / radiant / patchdialog.cpp
1 /*
2 Copyright (C) 1999-2007 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 //
23 // Patch Dialog
24 //
25 // Leonardo Zide (leo@lokigames.com)
26 //
27
28 #include <gdk/gdkkeysyms.h>
29 #include "stdafx.h"
30 #include "patchdialog.h"
31
32 PatchDialog g_PatchDialog;
33 // is the patch inspector currently displayed/active?
34 bool l_bIsActive = false;
35 // the increment we are using for the patch inspector (this is saved in the prefs)
36 texdef_t *l_pPIIncrement = &g_qeglobals.d_savedinfo.m_PIIncrement;
37
38 // =============================================================================
39 // static functions
40
41 static void OnDone (GtkWidget *widget, gpointer data)
42 {
43   g_PatchDialog.m_Patch = NULL;
44   g_PatchDialog.HideDlg ();
45 }
46
47 // memorize the current state (that is don't try to undo our do before changing something else)
48 static void OnApply (GtkWidget *widget, gpointer data)
49 {
50   g_PatchDialog.UpdateData(TRUE);
51   if (g_PatchDialog.m_Patch != NULL)
52   {
53     int r = g_PatchDialog.m_nRow;
54     int c = g_PatchDialog.m_nCol;
55     if (r >= 0 && r < g_PatchDialog.m_Patch->height && c >= 0 && c < g_PatchDialog.m_Patch->width)
56     {
57       if (g_PatchDialog.m_Patch->pShader)
58         g_PatchDialog.m_Patch->pShader->DecRef();
59         if (g_PatchDialog.m_strName.Find(' ') >= 0)
60         {
61           Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, dropping '%s'\n", g_PatchDialog.m_strName.GetBuffer());
62           g_PatchDialog.m_strName = SHADER_NOT_FOUND;
63         }
64         g_PatchDialog.m_Patch->pShader = QERApp_Shader_ForName(g_PatchDialog.m_strName);
65         g_PatchDialog.m_Patch->d_texture = g_PatchDialog.m_Patch->pShader->getTexture();
66         g_PatchDialog.m_Patch->ctrl[c][r].xyz[0] = g_PatchDialog.m_fX;
67         g_PatchDialog.m_Patch->ctrl[c][r].xyz[1] = g_PatchDialog.m_fY;
68         g_PatchDialog.m_Patch->ctrl[c][r].xyz[2] = g_PatchDialog.m_fZ;
69         g_PatchDialog.m_Patch->ctrl[c][r].st[0] = g_PatchDialog.m_fS;
70         g_PatchDialog.m_Patch->ctrl[c][r].st[1] = g_PatchDialog.m_fT;
71         g_PatchDialog.m_Patch->bDirty = true;
72         Sys_UpdateWindows(W_ALL);
73     }
74   }
75 }
76
77 static void OnSelchangeComboColRow (GtkWidget *widget, gpointer data)
78 {
79   if (!g_PatchDialog.m_bListenChanged)
80     return;
81 #ifdef DBG_PI
82   Sys_Printf("OnSelchangeComboColRow\n");
83 #endif
84   // retrieve the current m_nRow and m_nCol, other params are not relevant
85   // (NOTE: UpdateData has a mechanism to avoid inifinite looping)
86   g_PatchDialog.UpdateData(TRUE);
87   // read the changed values ourselves
88   g_PatchDialog.UpdateRowColInfo();
89   // now reflect our changes
90   g_PatchDialog.UpdateData(FALSE);
91 }
92
93 static void OnBtnPatchdetails (GtkWidget *widget, gpointer data)
94 {
95   Patch_NaturalizeSelected(true);
96   Sys_UpdateWindows(W_ALL);
97 }
98
99 static void OnBtnPatchfit (GtkWidget *widget, gpointer data)
100 {
101   Patch_ResetTexturing(1.0, 1.0);
102   Sys_UpdateWindows(W_ALL);
103 }
104
105 static void OnBtnPatchnatural (GtkWidget *widget, gpointer data)
106 {
107   Patch_NaturalizeSelected();
108   Sys_UpdateWindows(W_ALL);
109 }
110
111 static void OnBtnPatchreset (GtkWidget *widget, gpointer data)
112 {
113   float fx, fy;
114   if (DoTextureLayout (&fx, &fy) == IDOK)
115   {
116     Patch_ResetTexturing(fx, fy);
117   }
118   Sys_UpdateWindows(W_ALL);
119 }
120
121 static void OnSpinChanged (GtkAdjustment *adj, gpointer data)
122 {
123   texdef_t td;
124
125   td.rotate = 0;
126   td.scale[0] = td.scale[1] = 0;
127   td.shift[0] = td.shift[1] = 0;
128   td.contents = 0;
129   td.flags = 0;
130   td.value = 0;
131
132   if (adj->value == 0)
133     return;
134
135   if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hshift_adj"))
136   {
137     l_pPIIncrement->shift[0] = atof (gtk_entry_get_text (GTK_ENTRY (data)));
138
139     if (adj->value > 0)
140       td.shift[0] = l_pPIIncrement->shift[0];
141     else
142       td.shift[0] = -l_pPIIncrement->shift[0];
143   }
144   else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vshift_adj"))
145   {
146     l_pPIIncrement->shift[1] = atof (gtk_entry_get_text (GTK_ENTRY (data)));
147
148     if (adj->value > 0)
149       td.shift[1] = l_pPIIncrement->shift[1];
150     else
151       td.shift[1] = -l_pPIIncrement->shift[1];
152   }
153   else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hscale_adj"))
154   {
155     l_pPIIncrement->scale[0] = atof (gtk_entry_get_text (GTK_ENTRY (data)));
156         if (l_pPIIncrement->scale[0] == 0.0f)
157                 return;
158         // make sure scale factor is always >1 for increases and <1 for decreases
159     if (adj->value > 0)
160         {
161           if (l_pPIIncrement->scale[0] < 1)
162         td.scale[0] = l_pPIIncrement->scale[0];
163           else
164         td.scale[0] = 1.0f / l_pPIIncrement->scale[0];
165         }
166     else
167     {
168           if (l_pPIIncrement->scale[0] < 1)
169         td.scale[0] = 1.0f / l_pPIIncrement->scale[0];
170           else
171         td.scale[0] = l_pPIIncrement->scale[0];
172         }
173   }
174   else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vscale_adj"))
175   {
176     l_pPIIncrement->scale[1] = atof (gtk_entry_get_text (GTK_ENTRY (data)));
177         if (l_pPIIncrement->scale[1] == 0.0f)
178                 return;
179         // make sure scale factor is always >1 for increases and <1 for decreases
180     if (adj->value > 0)
181         {
182           if (l_pPIIncrement->scale[1] < 1)
183         td.scale[1] = l_pPIIncrement->scale[1];
184           else
185         td.scale[1] = 1.0f / l_pPIIncrement->scale[1];
186         }
187     else
188     {
189           if (l_pPIIncrement->scale[1] < 1)
190         td.scale[1] = 1.0f / l_pPIIncrement->scale[1];
191           else
192         td.scale[1] = l_pPIIncrement->scale[1];
193         }
194   }
195   else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "rotate_adj"))
196   {
197     l_pPIIncrement->rotate = atof (gtk_entry_get_text (GTK_ENTRY (data)));
198
199     if (adj->value > 0)
200       td.rotate = l_pPIIncrement->rotate;
201     else
202       td.rotate = -l_pPIIncrement->rotate;
203   }
204
205   adj->value = 0;
206
207 #ifdef DBG_PI
208         Sys_Printf("Patch_SetTextureInfo: %g %g %g %g %g\n", td.shift[0], td.shift[1],td.scale[0],td.scale[1],td.rotate );
209 #endif
210   // will scale shift rotate the patch accordingly
211   Patch_SetTextureInfo (&td);
212   // update the point-by-point view
213   OnSelchangeComboColRow(NULL,NULL);
214   Sys_UpdateWindows (W_CAMERA);
215 }
216
217 static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data)
218 {
219 #ifdef DBG_PI
220   Sys_Printf("OnDialogKey\n");
221 #endif
222   if (event->keyval == GDK_Return)
223   {
224     OnApply (NULL, NULL);
225     return TRUE;
226   }
227   else if (event->keyval == GDK_Escape)
228   {
229     OnDone (NULL, NULL);
230     return TRUE;
231   }
232   return FALSE;
233 }
234
235 // =============================================================================
236 // Global Functions
237
238 void DoPatchInspector()
239 {
240   // do we need to create the dialog?
241   if (g_PatchDialog.GetWidget() == NULL)
242   {
243     g_PatchDialog.Create();
244     g_PatchDialog.UpdateData (FALSE);
245   }
246   g_PatchDialog.GetPatchInfo();
247   if (!l_bIsActive)
248     g_PatchDialog.ShowDlg ();
249 }
250
251 void UpdatePatchInspector()
252 {
253   if (l_bIsActive)
254     g_PatchDialog.GetPatchInfo();
255 }
256
257 void TogglePatchInspector()
258 {
259   if (l_bIsActive)
260     OnDone(NULL,NULL);
261   else
262     DoPatchInspector();
263 }
264
265 // =============================================================================
266 // PatchDialog class
267
268 PatchDialog::PatchDialog ()
269 {
270   m_strName = "";
271   m_fS = 0.0f;
272   m_fT = 0.0f;
273   m_fX = 0.0f;
274   m_fY = 0.0f;
275   m_fZ = 0.0f;
276   m_nCol = 0;
277   m_nRow = 0;
278   m_Patch = NULL;
279   m_bListenChanged = true;
280 }
281
282 void PatchDialog::InitDefaultIncrement(texdef_t *tex)
283 {
284   tex->SetName(SHADER_NOT_FOUND);
285   tex->scale[0] = 0.5f;
286   tex->scale[1] = 0.5f;
287   tex->rotate = 45;
288   tex->shift[0] = 8.0f;
289   tex->shift[1] = 8.0f;
290 }
291
292 // we plug into HideDlg and ShowDlg to maintain the l_bIsActive flag
293 void PatchDialog::HideDlg()
294 {
295   l_bIsActive = false;
296   Dialog::HideDlg();
297 }
298
299 void PatchDialog::ShowDlg()
300 {
301   l_bIsActive = true;
302   Dialog::ShowDlg();
303 }
304
305 void PatchDialog::BuildDialog ()
306 {
307   GtkWidget *dlg, *vbox, *vbox2, *hbox, *hbox2, *frame, *table, *label;
308   GtkWidget *button, *entry, *spin, *combo;
309   GtkObject *adj;
310   char buf[32];
311
312   dlg = m_pWidget;
313
314   load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posPatchWnd);
315
316   gtk_window_set_title (GTK_WINDOW (dlg), "Patch Properties");
317   gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (OnDone), NULL);
318   // catch 'Esc' and 'Enter'
319   gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL);
320   gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget));
321
322
323   vbox = gtk_vbox_new (FALSE, 5);
324   gtk_widget_show (vbox);
325   gtk_container_add (GTK_CONTAINER (dlg), vbox);
326   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
327
328   hbox = gtk_hbox_new (FALSE, 5);
329   gtk_widget_show (hbox);
330   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
331
332   frame = gtk_frame_new ("Details");
333   gtk_widget_show (frame);
334   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
335
336   vbox2 = gtk_vbox_new (FALSE, 5);
337   gtk_widget_show (vbox2);
338   gtk_container_add (GTK_CONTAINER (frame), vbox2);
339   gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
340
341   table = gtk_table_new (2, 2, FALSE);
342   gtk_widget_show (table);
343   gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0);
344   gtk_table_set_row_spacings (GTK_TABLE (table), 5);
345   gtk_table_set_col_spacings (GTK_TABLE (table), 5);
346
347   label = gtk_label_new ("Row:");
348   gtk_widget_show (label);
349   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
350                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
351                     (GtkAttachOptions) (0), 0, 0);
352
353   label = gtk_label_new ("Column:");
354   gtk_widget_show (label);
355   gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
356                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
357                     (GtkAttachOptions) (0), 0, 0);
358
359   combo = gtk_combo_new ();
360   gtk_widget_show (combo);
361   gtk_table_attach (GTK_TABLE (table), combo, 0, 1, 1, 2,
362                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
363                     (GtkAttachOptions) (0), 0, 0);
364   gtk_widget_set_usize (combo, 60, -1);
365   gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE);
366   gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
367                       GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this);
368   AddDialogData (combo, &m_nRow, DLG_COMBO_INT);
369   m_pRowCombo = combo;
370
371   combo = gtk_combo_new ();
372   gtk_widget_show (combo);
373   gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2,
374                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
375                     (GtkAttachOptions) (0), 0, 0);
376   gtk_widget_set_usize (combo, 60, -1);
377   gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE);
378   gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
379                       GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this);
380   AddDialogData (combo, &m_nCol, DLG_COMBO_INT);
381   m_pColCombo = combo;
382
383   table = gtk_table_new (5, 2, FALSE);
384   gtk_widget_show (table);
385   gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0);
386   gtk_table_set_row_spacings (GTK_TABLE (table), 5);
387   gtk_table_set_col_spacings (GTK_TABLE (table), 5);
388
389   label = gtk_label_new ("X:");
390   gtk_widget_show (label);
391   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
392                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
393                     (GtkAttachOptions) (0), 0, 0);
394
395   label = gtk_label_new ("Y:");
396   gtk_widget_show (label);
397   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
398                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
399                     (GtkAttachOptions) (0), 0, 0);
400
401   label = gtk_label_new ("Z:");
402   gtk_widget_show (label);
403   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
404                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
405                     (GtkAttachOptions) (0), 0, 0);
406
407   label = gtk_label_new ("S:");
408   gtk_widget_show (label);
409   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
410                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
411                     (GtkAttachOptions) (0), 0, 0);
412
413   label = gtk_label_new ("T:");
414   gtk_widget_show (label);
415   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
416                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
417                     (GtkAttachOptions) (0), 0, 0);
418
419   entry = gtk_entry_new ();
420   gtk_widget_show (entry);
421   gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1,
422                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
423                     (GtkAttachOptions) (0), 0, 0);
424   AddDialogData (entry, &m_fX, DLG_ENTRY_FLOAT);
425
426   entry = gtk_entry_new ();
427   gtk_widget_show (entry);
428   gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2,
429                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
430                     (GtkAttachOptions) (0), 0, 0);
431   AddDialogData (entry, &m_fY, DLG_ENTRY_FLOAT);
432
433   entry = gtk_entry_new ();
434   gtk_widget_show (entry);
435   gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3,
436                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
437                     (GtkAttachOptions) (0), 0, 0);
438   AddDialogData (entry, &m_fZ, DLG_ENTRY_FLOAT);
439
440   entry = gtk_entry_new ();
441   gtk_widget_show (entry);
442   gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 3, 4,
443                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
444                     (GtkAttachOptions) (0), 0, 0);
445   AddDialogData (entry, &m_fS, DLG_ENTRY_FLOAT);
446
447   entry = gtk_entry_new ();
448   gtk_widget_show (entry);
449   gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 4, 5,
450                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
451                     (GtkAttachOptions) (0), 0, 0);
452   AddDialogData (entry, &m_fT, DLG_ENTRY_FLOAT);
453
454   frame = gtk_frame_new ("Texturing");
455   gtk_widget_show (frame);
456   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
457
458   vbox2 = gtk_vbox_new (FALSE, 5);
459   gtk_widget_show (vbox2);
460   gtk_container_add (GTK_CONTAINER (frame), vbox2);
461   gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
462
463   label = gtk_label_new ("Name:");
464   gtk_widget_show (label);
465   gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0);
466   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
467   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
468
469   entry = gtk_entry_new ();
470 //  gtk_entry_set_editable (GTK_ENTRY (entry), false);
471   gtk_widget_show (entry);
472   gtk_box_pack_start (GTK_BOX (vbox2), entry, TRUE, TRUE, 0);
473   AddDialogData (entry, &m_strName, DLG_ENTRY_TEXT);
474
475   table = gtk_table_new (5, 3, FALSE);
476   gtk_widget_show (table);
477   gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0);
478   gtk_table_set_row_spacings (GTK_TABLE (table), 5);
479   gtk_table_set_col_spacings (GTK_TABLE (table), 5);
480
481   label = gtk_label_new ("Horizontal Shift Step");
482   gtk_widget_show (label);
483   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
484                     (GtkAttachOptions) (GTK_FILL),
485                     (GtkAttachOptions) (0), 0, 0);
486   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
487
488   label = gtk_label_new ("Vertical Shift Step");
489   gtk_widget_show (label);
490   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2,
491                     (GtkAttachOptions) (GTK_FILL),
492                     (GtkAttachOptions) (0), 0, 0);
493   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
494
495   label = gtk_label_new ("Horizontal Stretch Step");
496   gtk_widget_show (label);
497   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3,
498                     (GtkAttachOptions) (GTK_FILL),
499                     (GtkAttachOptions) (0), 0, 0);
500   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
501
502   label = gtk_label_new ("Vertical Stretch Step");
503   gtk_widget_show (label);
504   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4,
505                     (GtkAttachOptions) (GTK_FILL),
506                     (GtkAttachOptions) (0), 0, 0);
507   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
508
509   label = gtk_label_new ("Rotate Step");
510   gtk_widget_show (label);
511   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5,
512                     (GtkAttachOptions) (GTK_FILL),
513                     (GtkAttachOptions) (0), 0, 0);
514   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
515
516   entry = gtk_entry_new ();
517   gtk_widget_show (entry);
518   gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 0, 1,
519                     (GtkAttachOptions) (GTK_FILL),
520                     (GtkAttachOptions) (0), 0, 0);
521   gtk_widget_set_usize (entry, 50, -2);
522   g_object_set_data (G_OBJECT (m_pWidget), "hshift_entry", entry);
523   // we fill in this data, if no patch is selected the widgets are unmodified when the inspector is raised
524   // so we need to have at least one initialisation somewhere
525   sprintf (buf, "%g", l_pPIIncrement->shift[0]);
526   gtk_entry_set_text (GTK_ENTRY (entry), buf);
527
528   adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1);
529   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry);
530   g_object_set_data (G_OBJECT (m_pWidget), "hshift_adj", adj);
531
532   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
533   gtk_widget_show (spin);
534   gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1,
535                     (GtkAttachOptions) (0),
536                     (GtkAttachOptions) (0), 0, 0);
537   gtk_widget_set_usize (spin, 10, -2);
538
539   entry = gtk_entry_new ();
540   gtk_widget_show (entry);
541   gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2,
542                     (GtkAttachOptions) (GTK_FILL),
543                     (GtkAttachOptions) (0), 0, 0);
544   gtk_widget_set_usize (entry, 50, -2);
545   sprintf (buf, "%g", l_pPIIncrement->shift[1]);
546   gtk_entry_set_text (GTK_ENTRY (entry), buf);
547
548   adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1);
549   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry);
550   g_object_set_data (G_OBJECT (m_pWidget), "vshift_adj", adj);
551
552   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
553   gtk_widget_show (spin);
554   gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2,
555                     (GtkAttachOptions) (0),
556                     (GtkAttachOptions) (0), 0, 0);
557   gtk_widget_set_usize (spin, 10, -2);
558
559   entry = gtk_entry_new ();
560   gtk_widget_show (entry);
561   gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 2, 3,
562                     (GtkAttachOptions) (GTK_FILL),
563                     (GtkAttachOptions) (0), 0, 0);
564   gtk_widget_set_usize (entry, 50, -2);
565   sprintf (buf, "%g", l_pPIIncrement->scale[0]);
566   gtk_entry_set_text (GTK_ENTRY (entry), buf);
567
568   adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1);
569   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry);
570   g_object_set_data (G_OBJECT (m_pWidget), "hscale_adj", adj);
571
572   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
573   gtk_widget_show (spin);
574   gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3,
575                     (GtkAttachOptions) (0),
576                     (GtkAttachOptions) (0), 0, 0);
577   gtk_widget_set_usize (spin, 10, -2);
578
579   entry = gtk_entry_new ();
580   gtk_widget_show (entry);
581   gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 3, 4,
582                     (GtkAttachOptions) (GTK_FILL),
583                     (GtkAttachOptions) (0), 0, 0);
584   gtk_widget_set_usize (entry, 50, -2);
585   sprintf (buf, "%g", l_pPIIncrement->scale[1]);
586   gtk_entry_set_text (GTK_ENTRY (entry), buf);
587
588   adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1);
589   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry);
590   g_object_set_data (G_OBJECT (m_pWidget), "vscale_adj", adj);
591
592   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
593   gtk_widget_show (spin);
594   gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4,
595                     (GtkAttachOptions) (0),
596                     (GtkAttachOptions) (0), 0, 0);
597   gtk_widget_set_usize (spin, 10, -2);
598
599   entry = gtk_entry_new ();
600   gtk_widget_show (entry);
601   gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 4, 5,
602                     (GtkAttachOptions) (GTK_FILL),
603                     (GtkAttachOptions) (0), 0, 0);
604   gtk_widget_set_usize (entry, 50, -2);
605   sprintf (buf, "%g", l_pPIIncrement->rotate);
606   gtk_entry_set_text (GTK_ENTRY (entry), buf);
607
608   adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1);   // NOTE: Arnout - this really should be 360 but can't change it anymore as it could break existing maps
609   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry);
610   g_object_set_data (G_OBJECT (m_pWidget), "rotate_adj", adj);
611
612   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
613   gtk_widget_show (spin);
614   gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5,
615                     (GtkAttachOptions) (0),
616                     (GtkAttachOptions) (0), 0, 0);
617   gtk_widget_set_usize (spin, 10, -2);
618
619   hbox2 = gtk_hbox_new (TRUE, 5);
620   gtk_widget_show (hbox2);
621   gtk_box_pack_start (GTK_BOX (vbox2), hbox2, TRUE, FALSE, 0);
622
623   button = gtk_button_new_with_label ("CAP");
624   gtk_widget_show (button);
625   gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0);
626   gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL);
627   gtk_widget_set_usize (button, 60, -1);
628
629   button = gtk_button_new_with_label ("Set...");
630   gtk_widget_show (button);
631   gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0);
632   gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL);
633   gtk_widget_set_usize (button, 60, -1);
634
635   button = gtk_button_new_with_label ("Natural");
636   gtk_widget_show (button);
637   gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0);
638   gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL);
639   gtk_widget_set_usize (button, 60, -1);
640
641   button = gtk_button_new_with_label ("Fit");
642   gtk_widget_show (button);
643   gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0);
644   gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchfit), NULL);
645   gtk_widget_set_usize (button, 60, -1);
646
647   hbox = gtk_hbox_new (FALSE, 5);
648   gtk_widget_show (hbox);
649   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0);
650
651   button = gtk_button_new_with_label ("Done");
652   gtk_widget_show (button);
653   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
654   gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnDone), NULL);
655   gtk_widget_set_usize (button, 60, -1);
656
657   button = gtk_button_new_with_label ("Apply");
658   gtk_widget_show (button);
659   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
660   gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnApply), NULL);
661   gtk_widget_set_usize (button, 60, -1);
662 }
663
664 // sync the dialog our internal data structures
665 void PatchDialog::UpdateData (bool retrieve)
666 {
667   if (m_pWidget == NULL)
668     return;
669
670   m_bListenChanged = false;
671   Dialog::UpdateData (retrieve);
672   m_bListenChanged = true;
673 }
674
675 // read the map and feed in the stuff to the dialog box
676 void PatchDialog::GetPatchInfo()
677 {
678   m_Patch = SinglePatchSelected();
679   if (m_Patch != NULL)
680   {
681     m_strName = m_Patch->pShader->getName();
682
683     GList *combo_list = NULL;
684     int i;
685
686     // fill in the numbers for Row / Col selection
687     m_bListenChanged = false;
688
689     for (i = 0; i < m_Patch->height; i++)
690       combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); // NOTE: leaving the g_strdup cause we free with g_free later on
691     gtk_combo_set_popdown_strings (GTK_COMBO (m_pRowCombo), combo_list);
692     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pRowCombo)->entry), "0");
693
694     while (combo_list)
695     {
696       g_free (combo_list->data);
697       combo_list = g_list_remove (combo_list, combo_list->data);
698     }
699
700     for (i = 0; i < m_Patch->width; i++)
701       combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i));
702     gtk_combo_set_popdown_strings (GTK_COMBO (m_pColCombo), combo_list);
703     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pColCombo)->entry), "0");
704
705     while (combo_list)
706     {
707       g_free (combo_list->data);
708       combo_list = g_list_remove (combo_list, combo_list->data);
709     }
710
711     m_bListenChanged = true;
712
713   }
714   else
715     Sys_Printf("WARNING: no patch\n");
716   // fill in our internal structs
717   m_nRow = 0; m_nCol = 0;
718   UpdateRowColInfo();
719   // now update the dialog box
720   UpdateData(false);
721 }
722
723 // read the current patch on map and initialize m_fX m_fY accordingly
724 // NOTE: don't call UpdateData in there, it's not meant for
725 void PatchDialog::UpdateRowColInfo()
726 {
727   m_fX = m_fY = m_fZ = m_fS = m_fT = 0.0;
728
729   if (m_Patch != NULL)
730   {
731     // we rely on whatever active row/column has been set before we get called
732     int r = m_nRow;
733     int c = m_nCol;
734     if (r >= 0 && r < m_Patch->height && c >= 0 && c < m_Patch->width)
735     {
736       m_fX = m_Patch->ctrl[c][r].xyz[0];
737       m_fY = m_Patch->ctrl[c][r].xyz[1];
738       m_fZ = m_Patch->ctrl[c][r].xyz[2];
739       m_fS = m_Patch->ctrl[c][r].st[0];
740       m_fT = m_Patch->ctrl[c][r].st[1];
741     }
742   }
743 }
744