]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bkgrnd2d/dialog.cpp
7bdf466aad9e0dbe4c2cf5c7c4840968b87dbf76
[xonotic/netradiant.git] / contrib / bkgrnd2d / dialog.cpp
1 /*
2    Copyright (C) 2003 Reed Mideke.
3
4    This file is part of GtkRadiant.
5
6    GtkRadiant is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    GtkRadiant is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GtkRadiant; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 //
22 // bkgrnd2d Plugin dialog
23 //
24 // Code by reyalP aka Reed Mideke
25 //
26 // Based on various other plugins
27 //
28
29 #include <gtk/gtk.h>
30
31 #include "bkgrnd2d.h"
32 #include "dialog.h"
33
34 // spaces to make label nice and big
35 #define NO_FILE_MSG "        (no file loaded)        "
36
37 static ui::Window pDialogWnd{ui::null};
38 static GtkWidget *pNotebook;
39 static GtkTooltips *pTooltips;
40
41 class CBackgroundDialogPage {
42 private:
43     GtkWidget *m_pWidget;
44     GtkWidget *m_pTabLabel;
45     ui::Label m_pFileLabel;
46     GtkWidget *m_pPosLabel;
47     VIEWTYPE m_vt;
48     bool m_bValidFile;
49
50 public:
51     CBackgroundImage *m_pImage;
52
53     CBackgroundDialogPage(VIEWTYPE vt);
54
55     void Append(GtkWidget *notebook);
56
57     void Browse();
58
59     void Reload();
60
61     void SetPosLabel();
62 //  ~BackgroundDialogPage();
63 };
64
65
66 // dialog page callbacks
67 static void browse_callback(GtkWidget *widget, gpointer data)
68 {
69     ((CBackgroundDialogPage *) data)->Browse();
70 }
71
72 static void reload_callback(GtkWidget *widget, gpointer data)
73 {
74     ((CBackgroundDialogPage *) data)->Reload();
75 }
76
77 static void size_sel_callback(GtkWidget *widget, gpointer data)
78 {
79     CBackgroundDialogPage *pPage = (CBackgroundDialogPage *) data;
80     if (pPage->m_pImage->SetExtentsSel()) {
81         pPage->SetPosLabel();
82     }
83 }
84
85 static void size_mm_callback(GtkWidget *widget, gpointer data)
86 {
87     CBackgroundDialogPage *pPage = (CBackgroundDialogPage *) data;
88     if (pPage->m_pImage->SetExtentsMM()) {
89         pPage->SetPosLabel();
90     }
91 }
92
93 static void alpha_adjust_callback(GtkWidget *widget, gpointer data)
94 {
95     CBackgroundDialogPage *pPage = (CBackgroundDialogPage *) data;
96     pPage->m_pImage->m_alpha = (float) gtk_range_get_value(GTK_RANGE(widget));
97     g_FuncTable.m_pfnSysUpdateWindows(W_XY);
98 }
99
100 void CBackgroundDialogPage::Reload()
101 {
102     if (m_bValidFile) {
103         m_pImage->Load(gtk_label_get_text(GTK_LABEL(m_pFileLabel)));
104     }
105 }
106
107 void CBackgroundDialogPage::Browse()
108 {
109     char browsedir[PATH_MAX];
110     const char *ct;
111     const char *newfile;
112     char *t;
113
114     //TODO GetMapName saves the map. eeep!
115     //also with no map, returns unnamed.map, otherwise returns full path
116 //      Syn_Printf(MSG_PREFIX "GetMapName() %s\n",
117 //                              g_FuncTable.m_pfnGetMapName());
118
119     ct = g_FuncTable.m_pfnReadProjectKey("basepath");
120     // TODO shouldn't need this stuff
121     if (!ct || !strlen(ct)) {
122         Syn_Printf(MSG_PREFIX "basepath = NULL or empty\n");
123         return;
124     }
125     Syn_Printf(MSG_PREFIX "basepath: %s\n", ct);
126     if (strlen(ct) >= PATH_MAX) {
127         Syn_Printf(MSG_PREFIX "base game dir too long\n");
128         return;
129     }
130
131     strcpy(browsedir, ct);
132     // make sure we have a trailing /
133     if (browsedir[strlen(browsedir) - 1] != '/') {
134         strcat(browsedir, "/");
135     }
136
137     //if we dont have a file yet, don't try to use it for default dir
138     if (m_bValidFile) {
139         // filename should always be a nice clean unix style relative path
140         ct = gtk_label_get_text(GTK_LABEL(m_pFileLabel));
141         strcat(browsedir, ct);
142         Syn_Printf(MSG_PREFIX "full path: %s\n", browsedir);
143
144         // lop off the file part
145         t = browsedir + strlen(browsedir) - 1;
146         while (t != browsedir && *t != '/') {
147             t--;
148         }
149         *t = 0;
150     }
151     Syn_Printf(MSG_PREFIX "browse directory %s\n", browsedir);
152
153 //does NOT need freeing contrary to include/qerplugin.h comments
154 //TODO bug/patch for comments
155 //TODO patern gets fucked up sometimes if empty
156 //http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=915
157     newfile = g_FuncTable.m_pfnFileDialog(pDialogWnd, TRUE,
158                                           "Load Background Image", browsedir, FILETYPE_KEY);
159     if (!newfile) {
160         Syn_Printf(MSG_PREFIX "newfile = NULL\n");
161         return;
162     }
163     Syn_Printf(MSG_PREFIX "newfile: %s\n", newfile);
164     newfile = g_FileSystemTable.m_pfnExtractRelativePath(newfile);
165
166     if (!newfile) {
167         Syn_Printf(MSG_PREFIX "newfile = NULL\n");
168         return;
169     }
170     Syn_Printf(MSG_PREFIX "newfile: %s\n", newfile);
171
172     if (m_pImage->Load(newfile)) {
173         m_bValidFile = true;
174         m_pFileLabel.text(newfile);
175     }
176 }
177
178 void CBackgroundDialogPage::SetPosLabel()
179 {
180     char s[64];
181     // TODO no snprintf ?
182     sprintf(s, "Size/Position (%d,%d) (%d,%d)", (int) (m_pImage->m_xmin),
183             (int) (m_pImage->m_ymin), (int) (m_pImage->m_xmax), (int) (m_pImage->m_ymax));
184     m_pPosLabel.text(s);
185 }
186
187 CBackgroundDialogPage::CBackgroundDialogPage(VIEWTYPE vt)
188 {
189     GtkWidget *w;
190
191     m_vt = vt;
192
193     m_bValidFile = false;
194
195     switch (m_vt) {
196         case XY:
197             m_pTabLabel = ui::Label("X/Y");
198             m_pImage = &backgroundXY;
199             break;
200         case XZ:
201             m_pTabLabel = ui::Label("X/Z");
202             m_pImage = &backgroundXZ;
203             break;
204         case YZ:
205             m_pTabLabel = ui::Label("Y/Z");
206             m_pImage = &backgroundYZ;
207             break;
208     }
209 // A vbox to hold everything
210     m_pWidget = ui::VBox(FALSE, 0);
211 // Frame for file row
212     auto frame = ui::Frame("File");
213     m_pWidget.pack_start(frame, FALSE, FALSE, 2);
214
215 // hbox for first row
216     auto hbox = ui::HBox(FALSE, 5);
217     gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
218     frame.add(hbox);
219
220 // label to display filename
221     m_pFileLabel = ui::Label(NO_FILE_MSG);
222     gtk_label_set_selectable(GTK_LABEL(m_pFileLabel), TRUE);
223 //TODO set min size ? done with spaces right now
224     hbox.pack_start(m_pFileLabel, TRUE, TRUE, 5);
225
226     m_pFileLabel.show();
227
228     w = ui::Button("Browse...");
229     w.connect("clicked", G_CALLBACK(browse_callback), (gpointer) this );
230     hbox.pack_start(w, FALSE, FALSE, 5);
231     gtk_tooltips_set_tip(pTooltips, w, "Select a file", NULL);
232     w.show();
233
234     w = ui::Button("Reload");
235     w.connect("clicked", G_CALLBACK(reload_callback), (gpointer) this );
236     // TODO disable until we have file
237     // gtk_widget_set_sensitive(w,FALSE);
238     gtk_tooltips_set_tip(pTooltips, w, "Reload current file", NULL);
239     hbox.pack_start(w, FALSE, FALSE, 5);
240     w.show();
241
242     hbox.show();
243     frame.show();
244
245 // second row (rendering options)
246     frame = ui::Frame("Rendering");
247     m_pWidget.pack_start(frame, FALSE, FALSE, 2);
248
249     hbox = ui::HBox(FALSE, 5);
250     gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
251     frame.add(hbox);
252
253     w = ui::Label("Vertex alpha:");
254     hbox.pack_start(w, FALSE, FALSE, 5);
255     w.show();
256
257     w = ui::HScale(0.0, 1.0, 0.01);
258     gtk_range_set_value(GTK_RANGE(w), 0.5);
259     gtk_scale_set_value_pos(GTK_SCALE(w), GTK_POS_LEFT);
260     w.connect("value-changed", G_CALLBACK(alpha_adjust_callback), (gpointer) this );
261     hbox.pack_start(w, TRUE, TRUE, 5);
262     gtk_tooltips_set_tip(pTooltips, w, "Set image transparancy", NULL);
263     w.show();
264
265     hbox.show();
266     frame.show();
267 // Third row (size and position)
268     frame = ui::Frame("Size/Position (undefined)");
269     m_pPosLabel = gtk_frame_get_label_widget(GTK_FRAME(frame));
270     m_pWidget.pack_start(frame, FALSE, FALSE, 2);
271
272     hbox = ui::HBox(FALSE, 5);
273     frame.add(hbox);
274     gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
275
276     w = ui::Button("from selection");
277     hbox.pack_start(w, TRUE, FALSE, 5);
278     w.connect("clicked", G_CALLBACK(size_sel_callback), (gpointer) this );
279     gtk_tooltips_set_tip(pTooltips, w,
280                          "Set the size of the image to the bounding rectangle of all selected brushes and entities",
281                          NULL);
282     w.show();
283
284     if (m_vt == XY) {
285         w = ui::Button("from map mins/maxs");
286         hbox.pack_start(w, TRUE, FALSE, 2);
287         w.connect("clicked", G_CALLBACK(size_mm_callback), (gpointer) this );
288         gtk_tooltips_set_tip(pTooltips, w,
289                              "Set the size of the image using the mapcoordsmins and mapcoordsmaxs keys of the worldspawn entity",
290                              NULL);
291         w.show();
292     }
293
294     hbox.show();
295     frame.show();
296
297     m_pWidget.show();
298 }
299
300 void CBackgroundDialogPage::Append(GtkWidget *notebook)
301 {
302     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), m_pWidget, m_pTabLabel);
303 }
304
305 // dialog global callbacks
306 /*
307    static gint expose_callback( GtkWidget *widget, gpointer data )
308    {
309     return FALSE;
310    }
311  */
312
313 static void response_callback(GtkWidget *widget, gint response, gpointer data)
314 {
315     if (response == GTK_RESPONSE_CLOSE) {
316         gtk_widget_hide(pDialogWnd);
317     }
318 }
319
320 static gint close_callback(GtkWidget *widget, gpointer data)
321 {
322     gtk_widget_hide(pDialogWnd);
323     return TRUE;
324 }
325
326 void InitBackgroundDialog()
327 {
328     CBackgroundDialogPage *pPage;
329
330     pDialogWnd = gtk_dialog_new_with_buttons("Background Images",
331                                              g_pMainWidget,
332                                              (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT),
333             // TODO dialog with no buttons
334             //                                                                            GTK_STOCK_CLOSE,
335             //                                                                            GTK_RESPONSE_CLOSE,
336                                              NULL);
337     pDialogWnd.connect("delete_event", G_CALLBACK(close_callback), NULL);
338     pDialogWnd.connect("response", G_CALLBACK(response_callback), NULL);
339 //  pDialogWnd.connect( "expose_event", G_CALLBACK( ci_expose ), NULL );
340
341     pTooltips = gtk_tooltips_new();
342
343     pNotebook = gtk_notebook_new();
344     pPage = new CBackgroundDialogPage(XY);
345     pPage->Append(pNotebook);
346     pPage = new CBackgroundDialogPage(XZ);
347     pPage->Append(pNotebook);
348     pPage = new CBackgroundDialogPage(YZ);
349     pPage->Append(pNotebook);
350
351     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pDialogWnd)->vbox), pNotebook, TRUE, TRUE, 0);
352
353     pNotebook.show();
354
355     gtk_widget_realize(pDialogWnd);
356 }
357
358 void ShowBackgroundDialog()
359 {
360     gtk_window_present(pDialogWnd);
361 }
362
363 void ShowBackgroundDialogPG(int page)
364 {
365     gtk_notebook_set_current_page(GTK_NOTEBOOK(pNotebook), page);
366     ShowBackgroundDialog();
367 }