X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=radiant%2Fpatchdialog.cpp;h=b4af86de07045c6523188238cab88a6254f95ac6;hp=8a6ff7cd0eb1e2cbf46c46178cf3644218476562;hb=a9e5bfdf2a458e89978ee52ebbd3711884b54b29;hpb=80378101101ca1762bbf5638a9e3566893096d8a diff --git a/radiant/patchdialog.cpp b/radiant/patchdialog.cpp index 8a6ff7cd..b4af86de 100644 --- a/radiant/patchdialog.cpp +++ b/radiant/patchdialog.cpp @@ -1,745 +1,1095 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// Patch Dialog -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include "stdafx.h" -#include "patchdialog.h" - -PatchDialog g_PatchDialog; -// is the patch inspector currently displayed/active? -bool l_bIsActive = false; -// the increment we are using for the patch inspector (this is saved in the prefs) -texdef_t *l_pPIIncrement = &g_qeglobals.d_savedinfo.m_PIIncrement; - -// ============================================================================= -// static functions - -static void OnDone (GtkWidget *widget, gpointer data) -{ - g_PatchDialog.m_Patch = NULL; - g_PatchDialog.HideDlg (); -} - -// memorize the current state (that is don't try to undo our do before changing something else) -static void OnApply (GtkWidget *widget, gpointer data) -{ - g_PatchDialog.UpdateData(TRUE); - if (g_PatchDialog.m_Patch != NULL) - { - int r = g_PatchDialog.m_nRow; - int c = g_PatchDialog.m_nCol; - if (r >= 0 && r < g_PatchDialog.m_Patch->height && c >= 0 && c < g_PatchDialog.m_Patch->width) - { - if (g_PatchDialog.m_Patch->pShader) - g_PatchDialog.m_Patch->pShader->DecRef(); - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=467 - if (g_PatchDialog.m_strName.Find(' ') >= 0) - { - Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, dropping '%s'\n", g_PatchDialog.m_strName.GetBuffer()); - g_PatchDialog.m_strName = SHADER_NOT_FOUND; - } - g_PatchDialog.m_Patch->pShader = QERApp_Shader_ForName(g_PatchDialog.m_strName); - g_PatchDialog.m_Patch->d_texture = g_PatchDialog.m_Patch->pShader->getTexture(); - g_PatchDialog.m_Patch->ctrl[c][r].xyz[0] = g_PatchDialog.m_fX; - g_PatchDialog.m_Patch->ctrl[c][r].xyz[1] = g_PatchDialog.m_fY; - g_PatchDialog.m_Patch->ctrl[c][r].xyz[2] = g_PatchDialog.m_fZ; - g_PatchDialog.m_Patch->ctrl[c][r].st[0] = g_PatchDialog.m_fS; - g_PatchDialog.m_Patch->ctrl[c][r].st[1] = g_PatchDialog.m_fT; - g_PatchDialog.m_Patch->bDirty = true; - Sys_UpdateWindows(W_ALL); - } - } -} - -static void OnSelchangeComboColRow (GtkWidget *widget, gpointer data) -{ - if (!g_PatchDialog.m_bListenChanged) - return; -#ifdef DBG_PI - Sys_Printf("OnSelchangeComboColRow\n"); -#endif - // retrieve the current m_nRow and m_nCol, other params are not relevant - // (NOTE: UpdateData has a mechanism to avoid inifinite looping) - g_PatchDialog.UpdateData(TRUE); - // read the changed values ourselves - g_PatchDialog.UpdateRowColInfo(); - // now reflect our changes - g_PatchDialog.UpdateData(FALSE); -} - -static void OnBtnPatchdetails (GtkWidget *widget, gpointer data) -{ - Patch_NaturalizeSelected(true); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchfit (GtkWidget *widget, gpointer data) -{ - Patch_ResetTexturing(1.0, 1.0); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchnatural (GtkWidget *widget, gpointer data) -{ - Patch_NaturalizeSelected(); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchreset (GtkWidget *widget, gpointer data) -{ - float fx, fy; - if (DoTextureLayout (&fx, &fy) == IDOK) - { - Patch_ResetTexturing(fx, fy); - } - Sys_UpdateWindows(W_ALL); -} - -static void OnSpinChanged (GtkAdjustment *adj, gpointer data) -{ - texdef_t td; - - td.rotate = 0; - td.scale[0] = td.scale[1] = 0; - td.shift[0] = td.shift[1] = 0; - td.contents = 0; - td.flags = 0; - td.value = 0; - - if (adj->value == 0) - return; - - if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hshift_adj")) - { - l_pPIIncrement->shift[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - - if (adj->value > 0) - td.shift[0] = l_pPIIncrement->shift[0]; - else - td.shift[0] = -l_pPIIncrement->shift[0]; - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vshift_adj")) - { - l_pPIIncrement->shift[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - - if (adj->value > 0) - td.shift[1] = l_pPIIncrement->shift[1]; - else - td.shift[1] = -l_pPIIncrement->shift[1]; - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hscale_adj")) - { - l_pPIIncrement->scale[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - if (l_pPIIncrement->scale[0] == 0.0f) - return; - // make sure scale factor is always >1 for increases and <1 for decreases - if (adj->value > 0) - { - if (l_pPIIncrement->scale[0] < 1) - td.scale[0] = l_pPIIncrement->scale[0]; - else - td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; - } - else - { - if (l_pPIIncrement->scale[0] < 1) - td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; - else - td.scale[0] = l_pPIIncrement->scale[0]; - } - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vscale_adj")) - { - l_pPIIncrement->scale[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - if (l_pPIIncrement->scale[1] == 0.0f) - return; - // make sure scale factor is always >1 for increases and <1 for decreases - if (adj->value > 0) - { - if (l_pPIIncrement->scale[1] < 1) - td.scale[1] = l_pPIIncrement->scale[1]; - else - td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; - } - else - { - if (l_pPIIncrement->scale[1] < 1) - td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; - else - td.scale[1] = l_pPIIncrement->scale[1]; - } - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "rotate_adj")) - { - l_pPIIncrement->rotate = atof (gtk_entry_get_text (GTK_ENTRY (data))); - - if (adj->value > 0) - td.rotate = l_pPIIncrement->rotate; - else - td.rotate = -l_pPIIncrement->rotate; - } - - adj->value = 0; - -#ifdef DBG_PI - Sys_Printf("Patch_SetTextureInfo: %g %g %g %g %g\n", td.shift[0], td.shift[1],td.scale[0],td.scale[1],td.rotate ); -#endif - // will scale shift rotate the patch accordingly - Patch_SetTextureInfo (&td); - // update the point-by-point view - OnSelchangeComboColRow(NULL,NULL); - Sys_UpdateWindows (W_CAMERA); -} - -static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ -#ifdef DBG_PI - Sys_Printf("OnDialogKey\n"); -#endif - if (event->keyval == GDK_Return) - { - OnApply (NULL, NULL); - return TRUE; - } - else if (event->keyval == GDK_Escape) - { - OnDone (NULL, NULL); - return TRUE; - } - return FALSE; -} - -// ============================================================================= -// Global Functions - -void DoPatchInspector() -{ - // do we need to create the dialog? - if (g_PatchDialog.GetWidget() == NULL) - { - g_PatchDialog.Create(); - g_PatchDialog.UpdateData (FALSE); - } - g_PatchDialog.GetPatchInfo(); - if (!l_bIsActive) - g_PatchDialog.ShowDlg (); -} - -void UpdatePatchInspector() -{ - if (l_bIsActive) - g_PatchDialog.GetPatchInfo(); -} - -void TogglePatchInspector() -{ - if (l_bIsActive) - OnDone(NULL,NULL); - else - DoPatchInspector(); -} - -// ============================================================================= -// PatchDialog class - -PatchDialog::PatchDialog () -{ - m_strName = ""; - m_fS = 0.0f; - m_fT = 0.0f; - m_fX = 0.0f; - m_fY = 0.0f; - m_fZ = 0.0f; - m_nCol = 0; - m_nRow = 0; - m_Patch = NULL; - m_bListenChanged = true; -} - -void PatchDialog::InitDefaultIncrement(texdef_t *tex) -{ - tex->SetName(SHADER_NOT_FOUND); - tex->scale[0] = 0.5f; - tex->scale[1] = 0.5f; - tex->rotate = 45; - tex->shift[0] = 8.0f; - tex->shift[1] = 8.0f; -} - -// we plug into HideDlg and ShowDlg to maintain the l_bIsActive flag -void PatchDialog::HideDlg() -{ - l_bIsActive = false; - Dialog::HideDlg(); -} - -void PatchDialog::ShowDlg() -{ - l_bIsActive = true; - Dialog::ShowDlg(); -} - -void PatchDialog::BuildDialog () -{ - GtkWidget *dlg, *vbox, *vbox2, *hbox, *hbox2, *frame, *table, *label; - GtkWidget *button, *entry, *spin, *combo; - GtkObject *adj; - char buf[32]; - - dlg = m_pWidget; - - load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posPatchWnd); - - gtk_window_set_title (GTK_WINDOW (dlg), "Patch Properties"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (OnDone), NULL); - // catch 'Esc' and 'Enter' - gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); - - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); - - frame = gtk_frame_new ("Details"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Row:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Column:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - combo = gtk_combo_new (); - gtk_widget_show (combo); - gtk_table_attach (GTK_TABLE (table), combo, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (combo, 60, -1); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", - GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); - AddDialogData (combo, &m_nRow, DLG_COMBO_INT); - m_pRowCombo = combo; - - combo = gtk_combo_new (); - gtk_widget_show (combo); - gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (combo, 60, -1); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", - GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); - AddDialogData (combo, &m_nCol, DLG_COMBO_INT); - m_pColCombo = combo; - - table = gtk_table_new (5, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("X:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Z:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("S:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("T:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fX, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fY, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fZ, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fS, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fT, DLG_ENTRY_FLOAT); - - frame = gtk_frame_new ("Texturing"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - label = gtk_label_new ("Name:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - entry = gtk_entry_new (); -// gtk_entry_set_editable (GTK_ENTRY (entry), false); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (vbox2), entry, TRUE, TRUE, 0); - AddDialogData (entry, &m_strName, DLG_ENTRY_TEXT); - - table = gtk_table_new (5, 3, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Horizontal Shift Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Vertical Shift Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Horizontal Stretch Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Vertical Stretch Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Rotate Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (m_pWidget), "hshift_entry", entry); - // we fill in this data, if no patch is selected the widgets are unmodified when the inspector is raised - // so we need to have at least one initialisation somewhere - sprintf (buf, "%g", l_pPIIncrement->shift[0]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "hshift_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->shift[1]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "vshift_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->scale[0]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "hscale_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->scale[1]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "vscale_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->rotate); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - 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 - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "rotate_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - hbox2 = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox2), hbox2, TRUE, FALSE, 0); - - button = gtk_button_new_with_label ("CAP"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Set..."); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Natural"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Fit"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchfit), NULL); - gtk_widget_set_usize (button, 60, -1); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0); - - button = gtk_button_new_with_label ("Done"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnDone), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Apply"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnApply), NULL); - gtk_widget_set_usize (button, 60, -1); -} - -// sync the dialog our internal data structures -void PatchDialog::UpdateData (bool retrieve) -{ - if (m_pWidget == NULL) - return; - - m_bListenChanged = false; - Dialog::UpdateData (retrieve); - m_bListenChanged = true; -} - -// read the map and feed in the stuff to the dialog box -void PatchDialog::GetPatchInfo() -{ - m_Patch = SinglePatchSelected(); - if (m_Patch != NULL) - { - m_strName = m_Patch->pShader->getName(); - - GList *combo_list = NULL; - int i; - - // fill in the numbers for Row / Col selection - m_bListenChanged = false; - - for (i = 0; i < m_Patch->height; i++) - 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 - gtk_combo_set_popdown_strings (GTK_COMBO (m_pRowCombo), combo_list); - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pRowCombo)->entry), "0"); - - while (combo_list) - { - g_free (combo_list->data); - combo_list = g_list_remove (combo_list, combo_list->data); - } - - for (i = 0; i < m_Patch->width; i++) - combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); - gtk_combo_set_popdown_strings (GTK_COMBO (m_pColCombo), combo_list); - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pColCombo)->entry), "0"); - - while (combo_list) - { - g_free (combo_list->data); - combo_list = g_list_remove (combo_list, combo_list->data); - } - - m_bListenChanged = true; - - } - else - Sys_Printf("WARNING: no patch\n"); - // fill in our internal structs - m_nRow = 0; m_nCol = 0; - UpdateRowColInfo(); - // now update the dialog box - UpdateData(false); -} - -// read the current patch on map and initialize m_fX m_fY accordingly -// NOTE: don't call UpdateData in there, it's not meant for -void PatchDialog::UpdateRowColInfo() -{ - m_fX = m_fY = m_fZ = m_fS = m_fT = 0.0; - - if (m_Patch != NULL) - { - // we rely on whatever active row/column has been set before we get called - int r = m_nRow; - int c = m_nCol; - if (r >= 0 && r < m_Patch->height && c >= 0 && c < m_Patch->width) - { - m_fX = m_Patch->ctrl[c][r].xyz[0]; - m_fY = m_Patch->ctrl[c][r].xyz[1]; - m_fZ = m_Patch->ctrl[c][r].xyz[2]; - m_fS = m_Patch->ctrl[c][r].st[0]; - m_fT = m_Patch->ctrl[c][r].st[1]; - } - } -} - +/* + Copyright (C) 1999-2006 Id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. + + This file is part of GtkRadiant. + + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// +// Patch Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "patchdialog.h" + +#include + +#include "itexdef.h" + +#include "debugging/debugging.h" + +#include "gtkutil/idledraw.h" +#include "gtkutil/entry.h" +#include "gtkutil/button.h" +#include "gtkutil/nonmodal.h" +#include "dialog.h" +#include "gtkdlgs.h" +#include "mainframe.h" +#include "patchmanip.h" +#include "patch.h" +#include "commands.h" +#include "preferences.h" +#include "signal/isignal.h" + + +#include + +// the increment we are using for the patch inspector (this is saved in the prefs) +struct pi_globals_t +{ + float shift[2]; + float scale[2]; + float rotate; + + pi_globals_t(){ + shift[0] = 8.0f; + shift[1] = 8.0f; + scale[0] = 0.5f; + scale[1] = 0.5f; + rotate = 45.0f; + } +}; + +pi_globals_t g_pi_globals; + +class PatchFixedSubdivisions +{ +public: +PatchFixedSubdivisions() : m_enabled( false ), m_x( 0 ), m_y( 0 ){ +} +PatchFixedSubdivisions( bool enabled, std::size_t x, std::size_t y ) : m_enabled( enabled ), m_x( x ), m_y( y ){ +} +bool m_enabled; +std::size_t m_x; +std::size_t m_y; +}; + +void Patch_getFixedSubdivisions( const Patch& patch, PatchFixedSubdivisions& subdivisions ){ + subdivisions.m_enabled = patch.m_patchDef3; + subdivisions.m_x = patch.m_subdivisions_x; + subdivisions.m_y = patch.m_subdivisions_y; +} + +const std::size_t MAX_PATCH_SUBDIVISIONS = 32; + +void Patch_setFixedSubdivisions( Patch& patch, const PatchFixedSubdivisions& subdivisions ){ + patch.undoSave(); + + patch.m_patchDef3 = subdivisions.m_enabled; + patch.m_subdivisions_x = subdivisions.m_x; + patch.m_subdivisions_y = subdivisions.m_y; + + if ( patch.m_subdivisions_x == 0 ) { + patch.m_subdivisions_x = 4; + } + else if ( patch.m_subdivisions_x > MAX_PATCH_SUBDIVISIONS ) { + patch.m_subdivisions_x = MAX_PATCH_SUBDIVISIONS; + } + if ( patch.m_subdivisions_y == 0 ) { + patch.m_subdivisions_y = 4; + } + else if ( patch.m_subdivisions_y > MAX_PATCH_SUBDIVISIONS ) { + patch.m_subdivisions_y = MAX_PATCH_SUBDIVISIONS; + } + + SceneChangeNotify(); + Patch_textureChanged(); + patch.controlPointsChanged(); +} + +class PatchGetFixedSubdivisions +{ +PatchFixedSubdivisions& m_subdivisions; +public: +PatchGetFixedSubdivisions( PatchFixedSubdivisions& subdivisions ) : m_subdivisions( subdivisions ){ +} +void operator()( Patch& patch ){ + Patch_getFixedSubdivisions( patch, m_subdivisions ); + SceneChangeNotify(); +} +}; + +void Scene_PatchGetFixedSubdivisions( PatchFixedSubdivisions& subdivisions ){ +#if 1 + if ( GlobalSelectionSystem().countSelected() != 0 ) { + Patch* patch = Node_getPatch( GlobalSelectionSystem().ultimateSelected().path().top() ); + if ( patch != 0 ) { + Patch_getFixedSubdivisions( *patch, subdivisions ); + } + } +#else + Scene_forEachVisibleSelectedPatch( PatchGetFixedSubdivisions( subdivisions ) ); +#endif +} + +class PatchSetFixedSubdivisions +{ +const PatchFixedSubdivisions& m_subdivisions; +public: +PatchSetFixedSubdivisions( const PatchFixedSubdivisions& subdivisions ) : m_subdivisions( subdivisions ){ +} +void operator()( Patch& patch ) const { + Patch_setFixedSubdivisions( patch, m_subdivisions ); +} +}; + +void Scene_PatchSetFixedSubdivisions( const PatchFixedSubdivisions& subdivisions ){ + UndoableCommand command( "patchSetFixedSubdivisions" ); + Scene_forEachVisibleSelectedPatch( PatchSetFixedSubdivisions( subdivisions ) ); +} + + +class Subdivisions +{ +public: +ui::CheckButton m_enabled; +ui::Entry m_horizontal; +ui::Entry m_vertical; +Subdivisions() : m_enabled( (GtkCheckButton *) 0 ), m_horizontal( ui::null ), m_vertical( ui::null ){ +} +void update(){ + PatchFixedSubdivisions subdivisions; + Scene_PatchGetFixedSubdivisions( subdivisions ); + + toggle_button_set_active_no_signal( m_enabled, subdivisions.m_enabled ); + + if ( subdivisions.m_enabled ) { + entry_set_int( m_horizontal, static_cast( subdivisions.m_x ) ); + entry_set_int( m_vertical, static_cast( subdivisions.m_y ) ); + gtk_widget_set_sensitive( m_horizontal , TRUE ); + gtk_widget_set_sensitive( m_vertical , TRUE ); + } + else + { + m_horizontal.text(""); + m_vertical.text(""); + gtk_widget_set_sensitive( m_horizontal , FALSE ); + gtk_widget_set_sensitive( m_vertical , FALSE ); + } +} +void cancel(){ + update(); +} +typedef MemberCaller CancelCaller; +void apply(){ + Scene_PatchSetFixedSubdivisions( + PatchFixedSubdivisions( + gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( m_enabled ) ) != FALSE, + static_cast( entry_get_int( m_horizontal ) ), + static_cast( entry_get_int( m_vertical ) ) + ) + ); +} +typedef MemberCaller ApplyCaller; +static void applyGtk( GtkToggleButton* toggle, Subdivisions* self ){ + self->apply(); +} +}; + +class PatchInspector : public Dialog +{ +ui::Window BuildDialog(); +Subdivisions m_subdivisions; +NonModalEntry m_horizontalSubdivisionsEntry; +NonModalEntry m_verticalSubdivisionsEntry; +public: +IdleDraw m_idleDraw; +WindowPositionTracker m_position_tracker; + +Patch *m_Patch; + +CopiedString m_strName; +float m_fS; +float m_fT; +float m_fX; +float m_fY; +float m_fZ; +/* float m_fHScale; + float m_fHShift; + float m_fRotate; + float m_fVScale; + float m_fVShift; */ +int m_nCol; +int m_nRow; +ui::ComboBoxText m_pRowCombo{ui::null}; +ui::ComboBoxText m_pColCombo{ui::null}; +std::size_t m_countRows; +std::size_t m_countCols; + +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +// NOTE: much more simple than blocking signals +bool m_bListenChanged; + +PatchInspector() : + m_horizontalSubdivisionsEntry( Subdivisions::ApplyCaller( m_subdivisions ), Subdivisions::CancelCaller( m_subdivisions ) ), + m_verticalSubdivisionsEntry( Subdivisions::ApplyCaller( m_subdivisions ), Subdivisions::CancelCaller( m_subdivisions ) ), + m_idleDraw( MemberCaller( *this ) ){ + m_fS = 0.0f; + m_fT = 0.0f; + m_fX = 0.0f; + m_fY = 0.0f; + m_fZ = 0.0f; + m_nCol = 0; + m_nRow = 0; + m_countRows = 0; + m_countCols = 0; + m_Patch = 0; + m_bListenChanged = true; + + m_position_tracker.setPosition( c_default_window_pos ); +} + +bool visible(){ + return GetWidget().visible(); +} + +// void UpdateInfo(); +// void SetPatchInfo(); +void GetPatchInfo(); +void UpdateSpinners( bool bUp, int nID ); +// read the current patch on map and initialize m_fX m_fY accordingly +void UpdateRowColInfo(); +// sync the dialog our internal data structures +// depending on the flag it will read or write +// we use m_nCol m_nRow m_fX m_fY m_fZ m_fS m_fT m_strName +// (NOTE: this doesn't actually commit stuff to the map or read from it) +void importData(); +void exportData(); +}; + +PatchInspector g_PatchInspector; + +void PatchInspector_constructWindow( ui::Window main_window ){ + g_PatchInspector.m_parent = main_window; + g_PatchInspector.Create(); +} +void PatchInspector_destroyWindow(){ + g_PatchInspector.Destroy(); +} + +void PatchInspector_queueDraw(){ + if ( g_PatchInspector.visible() ) { + g_PatchInspector.m_idleDraw.queueDraw(); + } +} + +void DoPatchInspector(){ + g_PatchInspector.GetPatchInfo(); + if ( !g_PatchInspector.visible() ) { + g_PatchInspector.ShowDlg(); + } +} + +void PatchInspector_toggleShown(){ + if ( g_PatchInspector.visible() ) { + g_PatchInspector.m_Patch = 0; + g_PatchInspector.HideDlg(); + } + else{ + DoPatchInspector(); + } +} + + +// ============================================================================= +// static functions + +// memorize the current state (that is don't try to undo our do before changing something else) +static void OnApply( ui::Widget widget, gpointer data ){ + g_PatchInspector.exportData(); + if ( g_PatchInspector.m_Patch != 0 ) { + UndoableCommand command( "patchSetTexture" ); + g_PatchInspector.m_Patch->undoSave(); + + if ( !texdef_name_valid( g_PatchInspector.m_strName.c_str() ) ) { + globalErrorStream() << "invalid texture name '" << g_PatchInspector.m_strName.c_str() << "'\n"; + g_PatchInspector.m_strName = texdef_name_default(); + } + g_PatchInspector.m_Patch->SetShader( g_PatchInspector.m_strName.c_str() ); + + std::size_t r = g_PatchInspector.m_nRow; + std::size_t c = g_PatchInspector.m_nCol; + if ( r < g_PatchInspector.m_Patch->getHeight() + && c < g_PatchInspector.m_Patch->getWidth() ) { + PatchControl& p = g_PatchInspector.m_Patch->ctrlAt( r,c ); + p.m_vertex[0] = g_PatchInspector.m_fX; + p.m_vertex[1] = g_PatchInspector.m_fY; + p.m_vertex[2] = g_PatchInspector.m_fZ; + p.m_texcoord[0] = g_PatchInspector.m_fS; + p.m_texcoord[1] = g_PatchInspector.m_fT; + g_PatchInspector.m_Patch->controlPointsChanged(); + } + } +} + +static void OnSelchangeComboColRow( ui::Widget widget, gpointer data ){ + if ( !g_PatchInspector.m_bListenChanged ) { + return; + } + // retrieve the current m_nRow and m_nCol, other params are not relevant + g_PatchInspector.exportData(); + // read the changed values ourselves + g_PatchInspector.UpdateRowColInfo(); + // now reflect our changes + g_PatchInspector.importData(); +} + +class PatchSetTextureRepeat +{ +float m_s, m_t; +public: +PatchSetTextureRepeat( float s, float t ) : m_s( s ), m_t( t ){ +} +void operator()( Patch& patch ) const { + patch.SetTextureRepeat( m_s, m_t ); +} +}; + +void Scene_PatchTileTexture_Selected( scene::Graph& graph, float s, float t ){ + Scene_forEachVisibleSelectedPatch( PatchSetTextureRepeat( s, t ) ); + SceneChangeNotify(); +} + +static void OnBtnPatchdetails( ui::Widget widget, gpointer data ){ + Patch_CapTexture(); +} + +static void OnBtnPatchfit( ui::Widget widget, gpointer data ){ + Patch_FitTexture(); +} + +static void OnBtnPatchnatural( ui::Widget widget, gpointer data ){ + Patch_NaturalTexture(); +} + +static void OnBtnPatchreset( ui::Widget widget, gpointer data ){ + Patch_ResetTexture(); +} + +static void OnBtnPatchFlipX( ui::Widget widget, gpointer data ){ + Patch_FlipTextureX(); +} + +static void OnBtnPatchFlipY( ui::Widget widget, gpointer data ){ + Patch_FlipTextureY(); +} + +struct PatchRotateTexture +{ + float m_angle; +public: + PatchRotateTexture( float angle ) : m_angle( angle ){ + } + void operator()( Patch& patch ) const { + patch.RotateTexture( m_angle ); + } +}; + +void Scene_PatchRotateTexture_Selected( scene::Graph& graph, float angle ){ + Scene_forEachVisibleSelectedPatch( PatchRotateTexture( angle ) ); +} + +class PatchScaleTexture +{ +float m_s, m_t; +public: +PatchScaleTexture( float s, float t ) : m_s( s ), m_t( t ){ +} +void operator()( Patch& patch ) const { + patch.ScaleTexture( m_s, m_t ); +} +}; + +float Patch_convertScale( float scale ){ + if ( scale > 0 ) { + return scale; + } + if ( scale < 0 ) { + return -1 / scale; + } + return 1; +} + +void Scene_PatchScaleTexture_Selected( scene::Graph& graph, float s, float t ){ + Scene_forEachVisibleSelectedPatch( PatchScaleTexture( Patch_convertScale( s ), Patch_convertScale( t ) ) ); +} + +class PatchTranslateTexture +{ +float m_s, m_t; +public: +PatchTranslateTexture( float s, float t ) + : m_s( s ), m_t( t ){ +} +void operator()( Patch& patch ) const { + patch.TranslateTexture( m_s, m_t ); +} +}; + +void Scene_PatchTranslateTexture_Selected( scene::Graph& graph, float s, float t ){ + Scene_forEachVisibleSelectedPatch( PatchTranslateTexture( s, t ) ); +} + +static void OnBtnPatchAutoCap( ui::Widget widget, gpointer data ){ + Patch_AutoCapTexture(); +} + +static void OnSpinChanged( GtkAdjustment *adj, gpointer data ){ + texdef_t td; + + td.rotate = 0; + td.scale[0] = td.scale[1] = 0; + td.shift[0] = td.shift[1] = 0; + + if ( gtk_adjustment_get_value(adj) == 0 ) { + return; + } + + if ( adj == g_object_get_data( G_OBJECT( g_PatchInspector.GetWidget() ), "hshift_adj" ) ) { + g_pi_globals.shift[0] = static_cast( atof( gtk_entry_get_text( GTK_ENTRY( data ) ) ) ); + + if ( gtk_adjustment_get_value(adj) > 0 ) { + td.shift[0] = g_pi_globals.shift[0]; + } + else{ + td.shift[0] = -g_pi_globals.shift[0]; + } + } + else if ( adj == g_object_get_data( G_OBJECT( g_PatchInspector.GetWidget() ), "vshift_adj" ) ) { + g_pi_globals.shift[1] = static_cast( atof( gtk_entry_get_text( GTK_ENTRY( data ) ) ) ); + + if ( gtk_adjustment_get_value(adj) > 0 ) { + td.shift[1] = g_pi_globals.shift[1]; + } + else{ + td.shift[1] = -g_pi_globals.shift[1]; + } + } + else if ( adj == g_object_get_data( G_OBJECT( g_PatchInspector.GetWidget() ), "hscale_adj" ) ) { + g_pi_globals.scale[0] = static_cast( atof( gtk_entry_get_text( GTK_ENTRY( data ) ) ) ); + if ( g_pi_globals.scale[0] == 0.0f ) { + return; + } + if ( gtk_adjustment_get_value(adj) > 0 ) { + td.scale[0] = g_pi_globals.scale[0]; + } + else{ + td.scale[0] = -g_pi_globals.scale[0]; + } + } + else if ( adj == g_object_get_data( G_OBJECT( g_PatchInspector.GetWidget() ), "vscale_adj" ) ) { + g_pi_globals.scale[1] = static_cast( atof( gtk_entry_get_text( GTK_ENTRY( data ) ) ) ); + if ( g_pi_globals.scale[1] == 0.0f ) { + return; + } + if ( gtk_adjustment_get_value(adj) > 0 ) { + td.scale[1] = g_pi_globals.scale[1]; + } + else{ + td.scale[1] = -g_pi_globals.scale[1]; + } + } + else if ( adj == g_object_get_data( G_OBJECT( g_PatchInspector.GetWidget() ), "rotate_adj" ) ) { + g_pi_globals.rotate = static_cast( atof( gtk_entry_get_text( GTK_ENTRY( data ) ) ) ); + + if ( gtk_adjustment_get_value(adj) > 0 ) { + td.rotate = g_pi_globals.rotate; + } + else{ + td.rotate = -g_pi_globals.rotate; + } + } + + gtk_adjustment_set_value(adj, 0); + + // will scale shift rotate the patch accordingly + + + if ( td.shift[0] || td.shift[1] ) { + UndoableCommand command( "patchTranslateTexture" ); + Scene_PatchTranslateTexture_Selected( GlobalSceneGraph(), td.shift[0], td.shift[1] ); + } + else if ( td.scale[0] || td.scale[1] ) { + UndoableCommand command( "patchScaleTexture" ); + Scene_PatchScaleTexture_Selected( GlobalSceneGraph(), td.scale[0], td.scale[1] ); + } + else if ( td.rotate ) { + UndoableCommand command( "patchRotateTexture" ); + Scene_PatchRotateTexture_Selected( GlobalSceneGraph(), td.rotate ); + } + + // update the point-by-point view + OnSelchangeComboColRow( ui::root ,0 ); +} + +static gint OnDialogKey( ui::Widget widget, GdkEventKey* event, gpointer data ){ + if ( event->keyval == GDK_KEY_Return ) { + OnApply( ui::root, 0 ); + return TRUE; + } + else if ( event->keyval == GDK_KEY_Escape ) { + g_PatchInspector.GetPatchInfo(); + return TRUE; + } + return FALSE; +} + +// ============================================================================= +// PatchInspector class + +ui::Window PatchInspector::BuildDialog(){ + ui::Window window = ui::Window(create_floating_window( "Patch Properties", m_parent )); + + m_position_tracker.connect( window ); + + global_accel_connect_window( window ); + + window_connect_focus_in_clear_focus_widget( window ); + + + { + auto vbox = ui::VBox( FALSE, 5 ); + gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); + vbox.show(); + window.add(vbox); + { + auto hbox = ui::HBox( FALSE, 5 ); + hbox.show(); + vbox.pack_start( hbox, TRUE, TRUE, 0 ); + { + auto vbox2 = ui::VBox( FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 0 ); + vbox2.show(); + hbox.pack_start( vbox2, TRUE, TRUE, 0 ); + { + auto frame = ui::Frame( "Details" ); + frame.show(); + vbox2.pack_start( frame, TRUE, TRUE, 0 ); + { + auto vbox3 = ui::VBox( FALSE, 5 ); + gtk_container_set_border_width( GTK_CONTAINER( vbox3 ), 5 ); + vbox3.show(); + frame.add(vbox3); + { + auto table = ui::Table( 2, 2, FALSE ); + table.show(); + vbox3.pack_start( table, TRUE, TRUE, 0 ); + gtk_table_set_row_spacings( table, 5 ); + gtk_table_set_col_spacings( table, 5 ); + { + auto label = ui::Label( "Row:" ); + label.show(); + table.attach(label, {0, 1, 0, 1}, {(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0)}, {0, 0}); + } + { + auto label = ui::Label( "Column:" ); + label.show(); + table.attach(label, {1, 2, 0, 1}, {(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0)}, {0, 0}); + } + { + auto combo = ui::ComboBoxText(ui::New); + combo.connect( "changed", G_CALLBACK( OnSelchangeComboColRow ), this ); + AddDialogData( *GTK_COMBO_BOX(combo), m_nRow ); + + combo.show(); + table.attach(combo, {0, 1, 1, 2}, {(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0)}, {0, 0}); + combo.dimensions(60, -1); + m_pRowCombo = combo; + } + + { + auto combo = ui::ComboBoxText(ui::New); + combo.connect( "changed", G_CALLBACK( OnSelchangeComboColRow ), this ); + AddDialogData( *GTK_COMBO_BOX(combo), m_nCol ); + + combo.show(); + table.attach(combo, {1, 2, 1, 2}, {(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0)}, {0, 0}); + combo.dimensions(60, -1); + m_pColCombo = combo; + } + } + auto table = ui::Table( 5, 2, FALSE ); + table.show(); + vbox3.pack_start( table, TRUE, TRUE, 0 ); + gtk_table_set_row_spacings( table, 5 ); + gtk_table_set_col_spacings( table, 5 ); + { + auto label = ui::Label( "X:" ); + label.show(); + table.attach(label, {0, 1, 0, 1}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto label = ui::Label( "Y:" ); + label.show(); + table.attach(label, {0, 1, 1, 2}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto label = ui::Label( "Z:" ); + label.show(); + table.attach(label, {0, 1, 2, 3}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto label = ui::Label( "S:" ); + label.show(); + table.attach(label, {0, 1, 3, 4}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto label = ui::Label( "T:" ); + label.show(); + table.attach(label, {0, 1, 4, 5}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 0, 1}, {GTK_EXPAND | GTK_FILL, 0}); + AddDialogData( *GTK_ENTRY(entry), m_fX ); + + entry.connect( "key_press_event", G_CALLBACK( OnDialogKey ), 0 ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 1, 2}, {GTK_EXPAND | GTK_FILL, 0}); + AddDialogData( *GTK_ENTRY(entry), m_fY ); + + entry.connect( "key_press_event", G_CALLBACK( OnDialogKey ), 0 ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 2, 3}, {GTK_EXPAND | GTK_FILL, 0}); + AddDialogData( *GTK_ENTRY(entry), m_fZ ); + + entry.connect( "key_press_event", G_CALLBACK( OnDialogKey ), 0 ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 3, 4}, {GTK_EXPAND | GTK_FILL, 0}); + AddDialogData( *GTK_ENTRY(entry), m_fS ); + + entry.connect( "key_press_event", G_CALLBACK( OnDialogKey ), 0 ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 4, 5}, {GTK_EXPAND | GTK_FILL, 0}); + AddDialogData( *GTK_ENTRY(entry), m_fT ); + + entry.connect( "key_press_event", G_CALLBACK( OnDialogKey ), 0 ); + } + } + } + if ( g_pGameDescription->mGameType == "doom3" ) { + auto frame = ui::Frame( "Tesselation" ); + frame.show(); + vbox2.pack_start( frame, TRUE, TRUE, 0 ); + { + auto vbox3 = ui::VBox( FALSE, 5 ); + gtk_container_set_border_width( GTK_CONTAINER( vbox3 ), 5 ); + vbox3.show(); + frame.add(vbox3); + { + auto table = ui::Table( 3, 2, FALSE ); + table.show(); + vbox3.pack_start( table, TRUE, TRUE, 0 ); + gtk_table_set_row_spacings( table, 5 ); + gtk_table_set_col_spacings( table, 5 ); + { + auto label = ui::Label( "Fixed" ); + label.show(); + table.attach(label, {0, 1, 0, 1}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto check = ui::CheckButton(GTK_CHECK_BUTTON( gtk_check_button_new() )); + check.show(); + table.attach(check, {1, 2, 0, 1}, {GTK_EXPAND | GTK_FILL, 0}); + m_subdivisions.m_enabled = check; + guint handler_id = check.connect( "toggled", G_CALLBACK( &Subdivisions::applyGtk ), &m_subdivisions ); + g_object_set_data( G_OBJECT( check ), "handler", gint_to_pointer( handler_id ) ); + } + { + auto label = ui::Label( "Horizontal" ); + label.show(); + table.attach(label, {0, 1, 1, 2}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 1, 2}, {GTK_EXPAND | GTK_FILL, 0}); + m_subdivisions.m_horizontal = entry; + m_horizontalSubdivisionsEntry.connect( entry ); + } + { + auto label = ui::Label( "Vertical" ); + label.show(); + table.attach(label, {0, 1, 2, 3}, {GTK_EXPAND | GTK_FILL, 0}); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {1, 2, 2, 3}, {GTK_EXPAND | GTK_FILL, 0}); + m_subdivisions.m_vertical = entry; + m_verticalSubdivisionsEntry.connect( entry ); + } + } + } + } + } + { + auto frame = ui::Frame( "Texturing" ); + frame.show(); + hbox.pack_start( frame, TRUE, TRUE, 0 ); + { + auto vbox2 = ui::VBox( FALSE, 5 ); + vbox2.show(); + frame.add(vbox2); + gtk_container_set_border_width( GTK_CONTAINER( vbox2 ), 5 ); + { + auto label = ui::Label( "Name:" ); + label.show(); + vbox2.pack_start( label, TRUE, TRUE, 0 ); + gtk_label_set_justify( label, GTK_JUSTIFY_LEFT ); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + auto entry = ui::Entry(ui::New); + // gtk_editable_set_editable (GTK_ENTRY (entry), false); + entry.show(); + vbox2.pack_start( entry, TRUE, TRUE, 0 ); + AddDialogData( *GTK_ENTRY(entry), m_strName ); + + entry.connect( "key_press_event", G_CALLBACK( OnDialogKey ), 0 ); + } + { + auto table = ui::Table( 5, 4, FALSE ); + table.show(); + vbox2.pack_start( table, TRUE, TRUE, 0 ); + gtk_table_set_row_spacings( table, 5 ); + gtk_table_set_col_spacings( table, 5 ); + { + auto label = ui::Label( "Horizontal Shift Step" ); + label.show(); + table.attach(label, {2, 4, 0, 1}, {GTK_FILL | GTK_EXPAND, 0}); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + auto label = ui::Label( "Vertical Shift Step" ); + label.show(); + table.attach(label, {2, 4, 1, 2}, {GTK_FILL | GTK_EXPAND, 0}); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + auto label = ui::Label( "Horizontal Stretch Step" ); + label.show(); + table.attach(label, {2, 3, 2, 3}, {GTK_FILL | GTK_EXPAND, 0}); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + auto button = ui::Button( "Flip" ); + button.show(); + table.attach(button, {3, 4, 2, 3}, {GTK_FILL, 0}); + button.connect( "clicked", G_CALLBACK( OnBtnPatchFlipX ), 0 ); + button.dimensions(60, -1); + } + { + auto label = ui::Label( "Vertical Stretch Step" ); + label.show(); + table.attach(label, {2, 3, 3, 4}, {GTK_FILL | GTK_EXPAND, 0}); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + auto button = ui::Button( "Flip" ); + button.show(); + table.attach(button, {3, 4, 3, 4}, {GTK_FILL, 0}); + button.connect( "clicked", G_CALLBACK( OnBtnPatchFlipY ), 0 ); + button.dimensions(60, -1); + } + { + auto label = ui::Label( "Rotate Step" ); + label.show(); + table.attach(label, {2, 4, 4, 5}, {GTK_FILL | GTK_EXPAND, 0}); + gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {0, 1, 0, 1}, {GTK_FILL, 0}); + entry.dimensions(50, -1); + g_object_set_data( G_OBJECT( window ), "hshift_entry", (void *) entry ); + // we fill in this data, if no patch is selected the widgets are unmodified when the inspector is raised + // so we need to have at least one initialisation somewhere + entry_set_float( entry, g_pi_globals.shift[0] ); + + auto adj = ui::Adjustment( 0, -8192, 8192, 1, 1, 0 ); + adj.connect( "value_changed", G_CALLBACK( OnSpinChanged ), (gpointer) entry ); + g_object_set_data( G_OBJECT( window ), "hshift_adj", (gpointer) adj ); + + auto spin = ui::SpinButton( adj, 1, 0 ); + spin.show(); + table.attach(spin, {1, 2, 0, 1}, {0, 0}); + spin.dimensions(10, -1); + gtk_widget_set_can_focus( spin, false ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {0, 1, 1, 2}, {GTK_FILL, 0}); + entry.dimensions(50, -1); + entry_set_float( entry, g_pi_globals.shift[1] ); + + auto adj = ui::Adjustment( 0, -8192, 8192, 1, 1, 0 ); + adj.connect( "value_changed", G_CALLBACK( OnSpinChanged ), entry ); + g_object_set_data( G_OBJECT( window ), "vshift_adj", (gpointer) adj ); + + auto spin = ui::SpinButton( adj, 1, 0 ); + spin.show(); + table.attach(spin, {1, 2, 1, 2}, {0, 0}); + spin.dimensions(10, -1); + gtk_widget_set_can_focus( spin, false ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {0, 1, 2, 3}, {GTK_FILL, 0}); + entry.dimensions(50, -1); + entry_set_float( entry, g_pi_globals.scale[0] ); + + auto adj = ui::Adjustment( 0, -1000, 1000, 1, 1, 0 ); + adj.connect( "value_changed", G_CALLBACK( OnSpinChanged ), entry ); + g_object_set_data( G_OBJECT( window ), "hscale_adj", (gpointer) adj ); + + auto spin = ui::SpinButton( adj, 1, 0 ); + spin.show(); + table.attach(spin, {1, 2, 2, 3}, {0, 0}); + spin.dimensions(10, -1); + gtk_widget_set_can_focus( spin, false ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {0, 1, 3, 4}, {GTK_FILL, 0}); + entry.dimensions(50, -1); + entry_set_float( entry, g_pi_globals.scale[1] ); + + auto adj = ui::Adjustment( 0, -1000, 1000, 1, 1, 0 ); + adj.connect( "value_changed", G_CALLBACK( OnSpinChanged ), entry ); + g_object_set_data( G_OBJECT( window ), "vscale_adj", (gpointer) adj ); + + auto spin = ui::SpinButton( adj, 1, 0 ); + spin.show(); + table.attach(spin, {1, 2, 3, 4}, {0, 0}); + spin.dimensions(10, -1); + gtk_widget_set_can_focus( spin, false ); + } + { + auto entry = ui::Entry(ui::New); + entry.show(); + table.attach(entry, {0, 1, 4, 5}, {GTK_FILL, 0}); + entry.dimensions(50, -1); + entry_set_float( entry, g_pi_globals.rotate ); + + auto adj = ui::Adjustment( 0, -1000, 1000, 1, 1, 0 ); // NOTE: Arnout - this really should be 360 but can't change it anymore as it could break existing maps + adj.connect( "value_changed", G_CALLBACK( OnSpinChanged ), entry ); + g_object_set_data( G_OBJECT( window ), "rotate_adj", (gpointer) adj ); + + auto spin = ui::SpinButton( adj, 1, 0 ); + spin.show(); + table.attach(spin, {1, 2, 4, 5}, {0, 0}); + spin.dimensions(10, -1); + gtk_widget_set_can_focus( spin, false ); + } + } + auto hbox2 = ui::HBox( TRUE, 5 ); + hbox2.show(); + vbox2.pack_start( hbox2, TRUE, FALSE, 0 ); + { + auto button = ui::Button( "Auto Cap" ); + button.show(); + hbox2.pack_end(button, TRUE, FALSE, 0); + button.connect( "clicked", G_CALLBACK( OnBtnPatchAutoCap ), 0 ); + button.dimensions(60, -1); + } + { + auto button = ui::Button( "CAP" ); + button.show(); + hbox2.pack_end(button, TRUE, FALSE, 0); + button.connect( "clicked", G_CALLBACK( OnBtnPatchdetails ), 0 ); + button.dimensions(60, -1); + } + { + auto button = ui::Button( "Set..." ); + button.show(); + hbox2.pack_end(button, TRUE, FALSE, 0); + button.connect( "clicked", G_CALLBACK( OnBtnPatchreset ), 0 ); + button.dimensions(60, -1); + } + { + auto button = ui::Button( "Natural" ); + button.show(); + hbox2.pack_end(button, TRUE, FALSE, 0); + button.connect( "clicked", G_CALLBACK( OnBtnPatchnatural ), 0 ); + button.dimensions(60, -1); + } + { + auto button = ui::Button( "Fit" ); + button.show(); + hbox2.pack_end(button, TRUE, FALSE, 0); + button.connect( "clicked", G_CALLBACK( OnBtnPatchfit ), 0 ); + button.dimensions(60, -1); + } + } + } + } + } + + return window; +} + +// sync the dialog our internal data structures +void PatchInspector::exportData(){ + m_bListenChanged = false; + Dialog::exportData(); + m_bListenChanged = true; +} +void PatchInspector::importData(){ + m_bListenChanged = false; + Dialog::importData(); + m_bListenChanged = true; +} + +// read the map and feed in the stuff to the dialog box +void PatchInspector::GetPatchInfo(){ + if ( g_pGameDescription->mGameType == "doom3" ) { + m_subdivisions.update(); + } + + if ( GlobalSelectionSystem().countSelected() == 0 ) { + m_Patch = 0; + } + else + { + m_Patch = Node_getPatch( GlobalSelectionSystem().ultimateSelected().path().top() ); + } + + if ( m_Patch != 0 ) { + m_strName = m_Patch->GetShader(); + + // fill in the numbers for Row / Col selection + m_bListenChanged = false; + + { + gtk_combo_box_set_active( m_pRowCombo, 0 ); + + for ( std::size_t i = 0; i < m_countRows; ++i ) + { + gtk_combo_box_text_remove( m_pRowCombo, gint( m_countRows - i - 1 ) ); + } + + m_countRows = m_Patch->getHeight(); + for ( std::size_t i = 0; i < m_countRows; ++i ) + { + char buffer[16]; + sprintf( buffer, "%u", Unsigned( i ) ); + gtk_combo_box_text_append_text( m_pRowCombo, buffer ); + } + + gtk_combo_box_set_active( m_pRowCombo, 0 ); + } + + { + gtk_combo_box_set_active( m_pColCombo, 0 ); + + for ( std::size_t i = 0; i < m_countCols; ++i ) + { + gtk_combo_box_text_remove( m_pColCombo, gint( m_countCols - i - 1 ) ); + } + + m_countCols = m_Patch->getWidth(); + for ( std::size_t i = 0; i < m_countCols; ++i ) + { + char buffer[16]; + sprintf( buffer, "%u", Unsigned( i ) ); + gtk_combo_box_text_append_text( m_pColCombo, buffer ); + } + + gtk_combo_box_set_active( m_pColCombo, 0 ); + } + + m_bListenChanged = true; + + } + else + { + //globalOutputStream() << "WARNING: no patch\n"; + } + // fill in our internal structs + m_nRow = 0; m_nCol = 0; + UpdateRowColInfo(); + // now update the dialog box + importData(); +} + +// read the current patch on map and initialize m_fX m_fY accordingly +// NOTE: don't call UpdateData in there, it's not meant for +void PatchInspector::UpdateRowColInfo(){ + m_fX = m_fY = m_fZ = m_fS = m_fT = 0.0; + + if ( m_Patch != 0 ) { + // we rely on whatever active row/column has been set before we get called + std::size_t r = m_nRow; + std::size_t c = m_nCol; + if ( r < m_Patch->getHeight() + && c < m_Patch->getWidth() ) { + const PatchControl& p = m_Patch->ctrlAt( r,c ); + m_fX = p.m_vertex[0]; + m_fY = p.m_vertex[1]; + m_fZ = p.m_vertex[2]; + m_fS = p.m_texcoord[0]; + m_fT = p.m_texcoord[1]; + } + } +} + + +void PatchInspector_SelectionChanged( const Selectable& selectable ){ + PatchInspector_queueDraw(); +} + + +#include "preferencesystem.h" + + +void PatchInspector_Construct(){ + GlobalCommands_insert( "PatchInspector", FreeCaller(), Accelerator( 'S', (GdkModifierType)GDK_SHIFT_MASK ) ); + + GlobalPreferenceSystem().registerPreference( "PatchWnd", WindowPositionTrackerImportStringCaller( g_PatchInspector.m_position_tracker ), WindowPositionTrackerExportStringCaller( g_PatchInspector.m_position_tracker ) ); + GlobalPreferenceSystem().registerPreference( "SI_PatchTexdef_Scale1", FloatImportStringCaller( g_pi_globals.scale[0] ), FloatExportStringCaller( g_pi_globals.scale[0] ) ); + GlobalPreferenceSystem().registerPreference( "SI_PatchTexdef_Scale2", FloatImportStringCaller( g_pi_globals.scale[1] ), FloatExportStringCaller( g_pi_globals.scale[1] ) ); + GlobalPreferenceSystem().registerPreference( "SI_PatchTexdef_Shift1", FloatImportStringCaller( g_pi_globals.shift[0] ), FloatExportStringCaller( g_pi_globals.shift[0] ) ); + GlobalPreferenceSystem().registerPreference( "SI_PatchTexdef_Shift2", FloatImportStringCaller( g_pi_globals.shift[1] ), FloatExportStringCaller( g_pi_globals.shift[1] ) ); + GlobalPreferenceSystem().registerPreference( "SI_PatchTexdef_Rotate", FloatImportStringCaller( g_pi_globals.rotate ), FloatExportStringCaller( g_pi_globals.rotate ) ); + + typedef FreeCaller1 PatchInspectorSelectionChangedCaller; + GlobalSelectionSystem().addSelectionChangeCallback( PatchInspectorSelectionChangedCaller() ); + typedef FreeCaller PatchInspectorQueueDrawCaller; + Patch_addTextureChangedCallback( PatchInspectorQueueDrawCaller() ); +} +void PatchInspector_Destroy(){ +}