]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/pk3man/mainwnd.cpp
* added pk3man and fixed it to compile for latest radiant
[xonotic/netradiant.git] / contrib / pk3man / mainwnd.cpp
1 // MainWnd.cpp: implementation of the CMainWnd class.
2 //
3 //////////////////////////////////////////////////////////////////////
4
5 #include "stdafx.h"
6 #include "mainwnd.h"
7 #include "memfile.h"
8 #include "md3.h"
9 #include "wild.h"
10 #include "renamedlg.h"
11 #ifdef __linux__
12 #include <dirent.h>
13 #include <stdlib.h>
14 #endif
15
16 extern CMainWnd *g_pMainWnd;
17 bool g_bIgnoreCommands=FALSE;
18
19 GtkWidget* create_menu_in_menu (GtkWidget *menu, gchar *label, GtkAccelGroup *menu_accel,GtkAccelGroup **submenu_accel);
20 GtkWidget* create_menu_item (GtkWidget *menu, gchar *label, GtkAccelGroup *menu_accel,GtkSignalFunc func, int id);
21 GtkWidget* menu_separator (GtkWidget *menu);
22
23 //////////////////////////////////////////////////////////////////////
24 // Construction/Destruction
25 //////////////////////////////////////////////////////////////////////
26
27 static gint mainwnd_delete (GtkWidget *widget, gpointer data)
28 {
29 return g_pMainWnd->OnClose();
30 }
31
32 static void HandleCommand (GtkWidget *widget, gpointer data)
33 {
34         int id = GPOINTER_TO_INT (data);
35
36         if (g_bIgnoreCommands)
37         return;
38
39         switch (id)
40         {
41                 case ID_FILE_NEW: g_pMainWnd->OnFileNew (); break;
42                 case ID_FILE_OPEN: g_pMainWnd->OnFileOpen (); break;
43                 case ID_FILE_SAVE: g_pMainWnd->OnFileSave (); break;
44
45                 case ID_WIZARD: g_pMainWnd->OnWizard (); break;
46
47                 case ID_VIEW: g_pMainWnd->OnView (); break;
48                 case ID_EXTRACT: g_pMainWnd->OnExtract (); break;
49
50                 case ID_ADD: g_pMainWnd->OnAdd (); break;
51                 case ID_RENAME: g_pMainWnd->OnRename (); break;
52                 case ID_DELETE: g_pMainWnd->OnDelete (); break;
53         }
54 }
55
56 CMainWnd::CMainWnd()
57 {
58         m_pMainWnd=NULL;
59         m_mnuDrop=NULL;
60 }
61
62 CMainWnd::~CMainWnd()
63 {
64         if (m_pMainWnd)
65                 delete m_pMainWnd;
66 }
67
68 bool CMainWnd::OnClose()
69 {
70         if (pak.IsModified())
71         {
72                 //int ret=DoMessageBox("Pk3 has not been saved\n\n    Really quit?","Pk3Man",MB_YESNO);
73                 int ret=g_FuncTable.m_pfnMessageBox(m_pMainWnd,"Pk3 has not been saved\n\n    Really quit?","Pk3Man",MB_YESNO, NULL);
74                 if (ret!=IDYES)
75                         return 1;
76         }
77
78         FreePakList();
79         DeleteTempFiles();
80         return 0;
81 }
82
83 void CMainWnd::OnDestroy()
84 {
85         // NOT CALLED !!!
86 }
87
88 BOOL CMainWnd::Create(GtkWidget *parent)
89 {
90         GtkWidget *vbox,*window;
91         GdkPixmap *pixmap=NULL;
92         GdkBitmap *mask=NULL;
93
94         char * icon_xpm[] = { "32 32 6 1", ".   c none", "/     c #ff0ff", "0   c #dddddd", "1  c #e6a0e6", "2  c #333333", "3  c #9d189d", "................................", "................................", "............////////............", "............////////............", "........////////////////........", "........////////////////........", "......////////////////////......", "......////////////////////......", "....//////0000////////0001//....", "....//////0000////////0000//....", "....////00000000////00000001....", "....////00000000////00000001....", "....////00002222////00002223....", "....////00002222////00002223....", "..//////00002222////00002223//..", "..//////00002222////00002222//..", "..////////0000////////0000////..", "..////////0000////////0000////..", "..////////////////////////////..", "..////////////////////////////..", "..////////////////////////////..", "..////////////////////////////..", "..////////////////////////////..", "..////////////////////////////..", "..////////////////////////////..", "..////////////////////////////..", "..////..//////....//////..////..", "..////..//////....//////..////..", "..//......////....////......//..", "..//......////....////......//..", "................................", "................................"};
95
96         // get bitmap paths
97         GetPaths();
98
99         // create the main widget
100         m_pMainWnd = window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
101         gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (mainwnd_delete), this);
102         //gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), this);
103
104         gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
105         gtk_window_set_title (GTK_WINDOW (m_pMainWnd), "Pk3Man - ");
106                 gtk_window_set_default_size (GTK_WINDOW (m_pMainWnd), 300, 300);
107                 gtk_widget_show (m_pMainWnd);
108
109         // load and set the icon
110
111         pixmap = gdk_pixmap_create_from_xpm_d (window->window, &mask, NULL, icon_xpm);
112         gdk_window_set_icon (window->window, NULL, pixmap, mask);
113
114         // setup the vertical layout box
115         vbox=gtk_vbox_new (FALSE, 0);
116         gtk_container_add (GTK_CONTAINER (window), vbox);
117         gtk_widget_show (vbox);
118
119         if (!CreateToolbar (window, vbox))
120                 return FALSE;
121
122         if (!CreateTreeView (window, vbox))
123                 return FALSE;
124
125         if (!CreateStatusBar (window,vbox))
126                 return FALSE;
127
128         UpdateStatus();
129         UpdateToolBar();
130
131         LoadExclusions();
132         InitPakList();
133
134         return TRUE;
135 }
136
137 BOOL CMainWnd::CreateTreeView(GtkWidget *window,GtkWidget *vbox)
138 {
139         // create a scrollable widget to house the tree
140         m_ScrolledWin = gtk_scrolled_window_new (NULL, NULL);
141         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_ScrolledWin),
142                                                                 GTK_POLICY_AUTOMATIC,
143                                                                 GTK_POLICY_AUTOMATIC);
144
145         //gtk_widget_set_usize (m_ScrolledWin, 400, 400);
146         gtk_box_pack_start (GTK_BOX (vbox), m_ScrolledWin, TRUE, TRUE, 0);
147         gtk_widget_show (m_ScrolledWin);
148
149         // attach and initialise the tree
150         m_Tree.Init(m_ScrolledWin);
151
152         return TRUE;
153 }
154
155 BOOL CMainWnd::CreateToolbar(GtkWidget *window,GtkWidget *vbox)
156 {
157         GtkWidget *handle_box, *toolbar, *w;
158
159         handle_box = gtk_handle_box_new ();
160         gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0);
161         gtk_widget_show (handle_box);
162
163         m_Toolbar = toolbar = gtk_toolbar_new ();
164
165         //  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style);
166         gtk_container_add (GTK_CONTAINER (handle_box), toolbar);
167         gtk_container_border_width (GTK_CONTAINER (toolbar), 2);
168         gtk_widget_show (toolbar);
169
170         // new
171         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
172                                                                 "New",
173                                                                 "Start a new Pk3",
174                                                                 "",
175                                                                 CPixMap::new_pixmap(window, "pk3man_tbnew.bmp"),
176                                                                 //CPixMap::pixmap_from_char(window,xpm_new),
177                                                                 GTK_SIGNAL_FUNC (HandleCommand),
178                                                                 GINT_TO_POINTER (ID_FILE_NEW));
179
180         gtk_object_set_data (GTK_OBJECT (window), "tb_file_new", w);
181
182         // open
183         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
184                                                                 "Open",
185                                                                 "Open an existing Pk3",
186                                                                 "",
187                                                                 CPixMap::new_pixmap(window, "pk3man_tbopen.bmp"),
188                                                                 GTK_SIGNAL_FUNC (HandleCommand),
189                                                                 GINT_TO_POINTER (ID_FILE_OPEN));
190
191         gtk_object_set_data (GTK_OBJECT (window), "tb_file_open", w);
192
193         // save
194         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
195                                                                 "Save",
196                                                                 "Save the current Pk3",
197                                                                 "",
198                                                                 CPixMap::new_pixmap (window, "pk3man_tbsave.bmp"),
199                                                                 GTK_SIGNAL_FUNC (HandleCommand),
200                                                                 GINT_TO_POINTER (ID_FILE_SAVE));
201
202         gtk_object_set_data (GTK_OBJECT (window), "tb_file_save", w);
203
204         // space
205         gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
206
207         // wizard
208         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
209                                                                 "Wizard",
210                                                                 "Build Pk3 from a Map",
211                                                                 "",
212                                                                 CPixMap::new_pixmap (window, "pk3man_tbwizard.bmp"),
213                                                                 GTK_SIGNAL_FUNC (HandleCommand),
214                                                                 GINT_TO_POINTER (ID_WIZARD));
215
216         gtk_object_set_data (GTK_OBJECT (window), "tb_wizard", w);
217
218         // space
219         gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
220
221         // view
222         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
223                                                                 "View",
224                                                                 "View an entry",
225                                                                 "",
226                                                                 CPixMap::new_pixmap (window, "pk3man_tbview.bmp"),
227                                                                 GTK_SIGNAL_FUNC (HandleCommand),
228                                                                 GINT_TO_POINTER (ID_VIEW));
229
230         gtk_object_set_data (GTK_OBJECT (window), "tb_view", w);
231
232         // extract
233         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
234                                                                 "Extract",
235                                                                 "Extract an entry",
236                                                                 "",
237                                                                 CPixMap::new_pixmap (window, "pk3man_tbextract.bmp"),
238                                                                 GTK_SIGNAL_FUNC (HandleCommand),
239                                                                 GINT_TO_POINTER (ID_EXTRACT));
240
241         gtk_object_set_data (GTK_OBJECT (window), "tb_extract", w);
242
243         // space
244         gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
245
246         // Add
247         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
248                                                                 "Wizard",
249                                                                 "Add a file",
250                                                                 "",
251                                                                 CPixMap::new_pixmap (window, "pk3man_tbadd.bmp"),
252                                                                 GTK_SIGNAL_FUNC (HandleCommand),
253                                                                 GINT_TO_POINTER (ID_ADD));
254
255         gtk_object_set_data (GTK_OBJECT (window), "tb_add", w);
256
257         // rename
258         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
259                                                                 "Rename",
260                                                                 "Rename an entry",
261                                                                 "",
262                                                                 CPixMap::new_pixmap (window, "pk3man_tbrename.bmp"),
263                                                                 GTK_SIGNAL_FUNC (HandleCommand),
264                                                                 GINT_TO_POINTER (ID_RENAME));
265
266         gtk_object_set_data (GTK_OBJECT (window), "tb_rename", w);
267
268
269         // rename
270         w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
271                                                                 "Delete",
272                                                                 "Delete an entry",
273                                                                 "",
274                                                                 CPixMap::new_pixmap (window, "pk3man_tbdelete.bmp"),
275                                                                 GTK_SIGNAL_FUNC (HandleCommand),
276                                                                 GINT_TO_POINTER (ID_DELETE));
277
278         gtk_object_set_data (GTK_OBJECT (window), "tb_delete", w);
279
280         return TRUE;
281 }
282
283 void CMainWnd::UpdateToolBar()
284 {
285         std::string path=m_Tree.GetSelected();
286         bool file_selected=TRUE;
287
288         if (path=="")
289                 file_selected=FALSE;
290
291         if (file_selected)
292         {
293                 // enable toolbar buttons
294
295                 GtkWidget *item;
296
297                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_view"));
298                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), FALSE);
299                 gtk_widget_set_sensitive (item, TRUE);
300
301                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_extract"));
302                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), FALSE);
303                 gtk_widget_set_sensitive (item, TRUE);
304
305                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_delete"));
306                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), FALSE);
307                 gtk_widget_set_sensitive (item, TRUE);
308
309                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_rename"));
310                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), FALSE);
311                 gtk_widget_set_sensitive (item, TRUE);
312
313         }
314         else
315         {
316                 // disable toolbar buttons
317
318                 GtkWidget *item;
319
320                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_view"));
321                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), TRUE);
322                 gtk_widget_set_sensitive (item, TRUE);
323
324                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_extract"));
325                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), TRUE);
326                 gtk_widget_set_sensitive (item, TRUE);
327
328                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_delete"));
329                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), TRUE);
330                 gtk_widget_set_sensitive (item, TRUE);
331
332                 item  = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (m_pMainWnd), "tb_rename"));
333                 //gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item), TRUE);
334                 gtk_widget_set_sensitive (item, TRUE);
335
336         }
337
338 }
339
340 BOOL CMainWnd::CreateStatusBar(GtkWidget *window,GtkWidget *vbox)
341 {
342         GtkWidget *hbox, *hbox1;
343         GtkWidget *frame;
344         GtkWidget *label;
345
346         hbox = gtk_hbox_new (FALSE, 0);
347         gtk_widget_show (hbox);
348         gtk_widget_set_usize (hbox, -1, 24);
349         gtk_container_border_width (GTK_CONTAINER (hbox), 1);
350         gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, TRUE, 2);
351
352         frame = gtk_frame_new ((char*)NULL);
353         gtk_widget_show (frame);
354         gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
355         gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
356
357         hbox1 = gtk_hbox_new (FALSE, 0);
358         gtk_container_add (GTK_CONTAINER (frame), hbox1);
359         gtk_container_border_width (GTK_CONTAINER (hbox1), 0);
360         gtk_widget_show (hbox1);
361
362         label = gtk_label_new (" Ready ... ");
363         gtk_widget_show (label);
364         gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, TRUE, 0);
365         gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
366         gtk_misc_set_padding (GTK_MISC (label), 3, 0);
367         m_pStatusLabel[0] = label;
368
369         for (int i = 1; i < 3; i++)
370         {
371                 frame = gtk_frame_new ((char*)NULL);
372                 gtk_widget_show (frame);
373                 gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
374                 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
375
376                 label = gtk_label_new ("             ");
377                 gtk_widget_show (label);
378                 gtk_container_add (GTK_CONTAINER (frame), label);
379                 m_pStatusLabel[i] = label;
380         }
381
382         return TRUE;
383 }
384
385 void CMainWnd::OnFileOpen()
386 {
387         // lets pick a file
388         const char *filename;
389
390         if (g_strModPath.GetLength()>0)
391                 //filename=file_dialog(TRUE,"Choose a Pk3...",g_strModPath.GetBuffer(),"*.pk3");
392                 filename=g_FuncTable.m_pfnFileDialog (m_pMainWnd, TRUE, "Choose a Pk3...",
393                                                                                         g_strModPath.GetBuffer(), "pk3man");
394         else
395                 //filename=file_dialog(TRUE,"Choose a Pk3...",g_strBasePath.GetBuffer(),"*.pk3");
396                 filename=g_FuncTable.m_pfnFileDialog (m_pMainWnd, TRUE, "Choose a Pk3...",
397                                                                                         g_strBasePath.GetBuffer(), "pk3man");
398
399         if (filename==NULL)
400                 return;
401
402         Str fname=filename;
403         fname=fname.Right(3);
404         if (fname!="pk3")
405         {
406                 //DoMessageBox("Please pick a Pk3 file","Pk3Man",MB_OK);
407                 g_FuncTable.m_pfnMessageBox(m_pMainWnd,"Please pick a Pk3 file","Pk3Man",MB_OK, NULL);
408                 return;
409         }
410
411         OnFileNew();
412         pak.Open(filename);
413         UpdateTree();
414
415         // update window title
416         g_FuncTable.m_pfnQE_ConvertDOSToUnixName (filename, filename);
417         std::string title=filename;
418         g_free (filename);
419         long pos=title.find_last_of('/');
420         title=title.substr(pos+1);
421         title="Pk3Man - "+title;
422         gtk_window_set_title (GTK_WINDOW (m_pMainWnd), title.c_str());
423 }
424
425 void CMainWnd::OnFileSave()
426 {
427         const char *filename;
428
429         if (g_strModPath.GetLength()>0)
430                 filename=g_FuncTable.m_pfnFileDialog (m_pMainWnd, FALSE, "Save As...",
431                                                                                         g_strModPath.GetBuffer(), "pk3man");
432         else
433                 filename=g_FuncTable.m_pfnFileDialog (m_pMainWnd, FALSE, "Save As...",
434                                                                                 g_strBasePath.GetBuffer(), "pk3man");
435
436         if (filename==NULL)
437                 return;
438
439         g_FuncTable.m_pfnQE_ConvertDOSToUnixName (filename, filename);
440         std::string path=filename;
441         g_free (filename);
442         long p=path.find_last_of('/');
443         std::string name=path.substr(p,-1);
444
445         std::string tpath=g_strTempPath.GetBuffer() + name;
446
447         if (!pak.Save(tpath.c_str()))
448         {
449                 // eek, error central
450                 g_FuncTable.m_pfnMessageBox(m_pMainWnd,"Unable to save the pk3 to temp folder!","Pk3Man",MB_OK, NULL);
451                 return;
452         }
453
454         // ok, now copy to proper place
455
456 #ifdef WIN32
457
458         int ret=CopyFile(tpath.c_str(),path.c_str(),FALSE);
459         DeleteFile(tpath.c_str());
460
461         if (!ret)
462         {
463         g_FuncTable.m_pfnMessageBox(m_pMainWnd,"Unable to copy pk3 from temp folder!","Pk3Man",MB_OK, NULL);
464         return;
465         }
466
467 #endif
468
469         pak.Close();
470         pak.Open(path.c_str());
471         m_Tree.Clear();
472         UpdateTree();
473
474         //update title
475         name=name.substr(1,-1);
476         std::string title="Pk3Man - "+name;
477         gtk_window_set_title (GTK_WINDOW (m_pMainWnd), title.c_str());
478 }
479
480 bool CMainWnd::OnFileNew()
481 {
482         if (pak.IsModified())
483         {
484                 int ret=g_FuncTable.m_pfnMessageBox(m_pMainWnd,"This will lose the current Pk3 contents\n\n    Are u sure?","Pk3Man",MB_YESNO, NULL);
485                 if (ret!=IDYES)
486                         return FALSE;
487         }
488
489         pak.Close();
490         m_Tree.Clear();
491         gtk_window_set_title (GTK_WINDOW (m_pMainWnd), "Pk3Man - ");
492
493         return TRUE;
494 }
495
496 void CMainWnd::LoadExclusions()
497 {
498         exclusions.clear();
499
500         FILE *fp;
501         std::string filename=g_strAppPath.GetBuffer();
502         filename+="plugins/pk3man.exclude";
503
504         fp=fopen(filename.c_str(),"rb");
505         if (!fp)
506                 return;
507
508         while (!feof(fp))
509         {
510                 std::string line=GetLine(fp);
511
512                 if (line.length()==0)
513                         continue;
514
515                 if (line[0]=='/' && line[1]=='/')
516                         continue;
517
518                 for (int n=0 ; n < (int)line.length() ; n++)
519                 {
520                         if (line[n]=='\\')
521                                 line[n]='/';
522                 }
523
524                 if (line[0]=='/')
525                         line=line.substr(1,-1);
526
527                 exclusions.push_back(line);
528         }
529 }
530
531 bool CMainWnd::IsExcluded(const char *name)
532 {
533         for (std::list<std::string>::iterator i=exclusions.begin() ; i!=exclusions.end() ; i++)
534         {
535                 std::string t=*i;
536
537                 if (CWild::fpattern_match(t.c_str(),name))
538                         return TRUE;
539
540                 std::string nm=name;
541                 if (nm.find(t) != static_cast<size_t>(-1))
542                         return TRUE;
543         }
544
545         return FALSE;
546 }
547
548 void CMainWnd::OnWizard()
549 {
550         if (!pak.IsEmpty())
551         {
552                 int ret=g_FuncTable.m_pfnMessageBox(m_pMainWnd,"Add to current pak contents ?","Pk3Man",MB_YESNO, NULL);
553                 if (ret==IDNO)
554                 {
555                         if (!OnFileNew())
556                                 return;
557                 }
558
559         }
560
561         std::string mappath="maps";
562         mappath=g_strBasePath.GetBuffer()+mappath;
563
564         gchar *filename=g_FuncTable.m_pfnFileDialog(m_pMainWnd,TRUE,"Choose a Map...",mappath.c_str(),"pk3man");
565
566         if (filename==NULL)
567                         return;
568
569         g_FuncTable.m_pfnQE_ConvertDOSToUnixName (filename, filename);
570         std::string map=filename;
571         long p=map.find_last_of('/');
572         map=map.substr(p+1,-1);
573
574         //update title
575         std::string title="Pk3Man - "+map;
576         gtk_window_set_title (GTK_WINDOW (m_pMainWnd), title.c_str());
577
578         // add map and aas
579         ProcessFile(map.c_str(),".bsp","maps");
580         ProcessFile(map.c_str(),".aas","maps");
581
582         // add levelshots
583         if (!ProcessFile(map.c_str(),".jpg","levelshots"))
584                 ProcessFile(map.c_str(),".tga","levelshots");
585
586         // arena file
587         ProcessFile(map.c_str(),".arena","scripts");
588
589         // initialise text list
590         texlist.clear();
591
592         // generate item list
593         FILE *fp;
594         fp=fopen(filename,"r");
595         g_free(filename);
596
597         if (!fp)
598                 return;
599
600         while (!feof(fp))
601         {
602                 std::string line=GetLine(fp);
603
604                 if (line.find("// brush")!=static_cast<size_t>(-1))
605                 {
606                         // its a brush
607                         line=GetLine(fp);
608                         line=GetLine(fp);
609
610                         if (line.find("patchDef")!=static_cast<size_t>(-1))
611                         {
612                                 // its a patch
613                                 line=GetLine(fp);
614                                 line=GetLine(fp);
615
616                                 // need to trim left and right
617                                 int n=line.find_first_not_of(' ');
618                                 if (n!=static_cast<size_t>(-1))
619                                 line=line.substr(n);
620
621                                 std::string tex="textures/"+line;
622                                 AddToTexList(line.c_str());
623                         }
624                         else
625                         {
626                                 // its a standard brush
627                                 while (line.find_first_of('}')==static_cast<size_t>(-1))
628                                 {
629                                         long p=line.find_last_of(')');
630                                         line=line.substr(p+2,-1);
631
632                                         p=line.find_first_of(' ');
633                                         line=line.substr(0,p);
634
635                                         std::string tex="textures/"+line;
636                                         AddToTexList(line.c_str());
637
638                                         // next
639                                         line=GetLine(fp);
640                                 }
641                         }
642                 }
643                 else if (line.find(".md3")!=static_cast<size_t>(-1))
644                 {
645                         long p=line.find_first_of(' ');
646                         std::string tex=line.substr(p+2,-1);
647                         tex=tex.substr(0,tex.length()-2);
648
649                         AddToTexList(tex.c_str());
650                 }
651                 else if (line.find(".wav")!=static_cast<size_t>(-1))
652                 {
653                         long p=line.find_first_of(' ');
654                         std::string tex=line.substr(p+2,-1);
655                         tex=tex.substr(0,tex.length()-2);
656
657                         AddToTexList(tex.c_str());
658                 }
659
660         }
661         fclose(fp);
662
663         // ok, now proccess our texlist
664         // if we find a shader we add its textures onto the end of the texlist
665
666         for ( std::list<std::string>::const_iterator i = texlist.begin() ; i != texlist.end() ; i++)
667         {
668                 std::string tex=*i;
669
670                 if (tex=="")
671                         continue;
672
673                 std::string suffix=tex.substr(tex.length()-3,-1);
674
675                 // is it a model?
676                 if (suffix.compare("md3")==0)
677                 {
678                         ParseModel(tex.c_str());
679
680                         // dont add md3's
681                         continue;
682                 }
683
684                 // does it exist as it is
685                 if (ProcessFile(tex.c_str()))
686                         continue;
687
688                 //shader
689                 std::string shadername=tex;
690                 const char *sname=NULL;
691
692                 IShader *shader=g_ShadersTable.m_pfnShader_ForName_NoLoad(shadername.c_str());
693
694                 if (shader)
695                         sname=shader->getShaderFileName();
696
697                 if (strlen(sname)>0)
698                 {
699                         ParseShader(sname,tex.c_str());
700
701                         if (ProcessFile(sname))
702                                 continue;
703                 }
704
705                 // ok we got this far, its a texture
706
707                 if (tex.find(".tga")!=static_cast<size_t>(-1) || tex.find(".jpg")!=static_cast<size_t>(-1))
708                         tex=tex.substr(0,tex.length()-4);
709
710                 // jpegs
711                 std::string jpeg=tex;
712                 if (jpeg.find("textures/")!=0)
713                         jpeg="textures/"+jpeg;
714
715                 jpeg+=".jpg";
716                 if (ProcessFile(jpeg.c_str()))
717                         continue;
718
719                 // tga's
720                 std::string tga=tex;
721                 if (tga.find("textures/")!=0)
722                         tga="textures/"+tga;
723
724                 tga+=".tga";
725                 if (ProcessFile(tga.c_str()))
726                         continue;
727
728         }
729
730 }
731
732 void CMainWnd::ParseModel(const char *pathname)
733 {
734         char* modelbuff;
735         int len = g_FuncTable.m_pfnLoadFile(pathname, (void**)&modelbuff);
736
737         if (len==0)
738                 return;
739
740         CMemFile file(modelbuff,len);
741
742         md3_header_t header;
743
744         file.Read(&header,sizeof(header));
745
746         int n, numtags=header.Tag_num*header.BoneFrame_num;
747
748         for (n=0 ; n<numtags ; n++)
749         {
750                 md3_tag_t tag;
751                 file.Read(&tag,sizeof(md3_tag_t));
752         }
753
754         for (n=0 ; n<header.BoneFrame_num ; n++)
755         {
756                 md3_boneframe_t bone;
757                 file.Read(&bone,sizeof(md3_boneframe_t));
758         }
759
760         for (int m=0 ; m<header.Mesh_num ; m++)
761         {
762                 md3_mesh_t mesh;
763                 file.Read(&mesh,sizeof(md3_mesh_t));
764
765                 // skins
766                 for (n=0 ; n<mesh.Skin_num ; n++)
767                 {
768                         char SkinName[68];
769                         file.Read(&SkinName,sizeof(char)*68);
770
771                         // deal with the skin here
772                         // we add it to the end of the list (if it aint already there)
773                         // so we catch it later on
774
775                         AddToTexList(SkinName);
776                 }
777
778                 // triangles
779                 for (n=0 ; n<mesh.Triangle_num ; n++)
780                 {
781                         int Triangle[3];
782                         file.Read(&Triangle,sizeof(int)*3);
783                 }
784
785                 // uv's
786                 for (n=0 ; n<mesh.Vertex_num ; n++)
787                 {
788                         float uv[2];
789                         file.Read(&uv,sizeof(float)*2);
790                 }
791
792                 // vertices
793                 int numverts=mesh.Vertex_num*mesh.MeshFrame_num;
794
795                 for (n=0 ; n<numverts ; n++)
796                 {
797                         md3_vertices_t verts;
798                         file.Read(&verts,sizeof(md3_vertices_t));
799                 }
800
801         }
802
803 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491
804 g_free(modelbuff);
805 }
806
807 void CMainWnd::AddToTexList(const char *buf)
808 {
809         std::string tex;
810         int c=0;
811
812         while (buf[c]!=' ' && buf[c]!='\0')
813         {
814                 tex+=buf[c];
815                 c++;
816         }
817
818         if (!IsInTexList(tex.c_str()))
819                 texlist.push_back(tex);
820
821 }
822
823 void CMainWnd::InitPaksInDir(const char *folder)
824 {
825 struct dirent *dirlist;
826 DIR *dir;
827
828 dir = opendir (g_strBasePath.GetBuffer());
829
830 if (dir != NULL)
831 {
832         while ((dirlist = readdir (dir)) != NULL)
833         {
834                 if (!strstr (dirlist->d_name, ".pk3"))
835                         continue;
836
837                 std::string path=g_strBasePath.GetBuffer();
838                 path+=dirlist->d_name;
839
840                 if (IsExcluded(dirlist->d_name))
841                         continue;
842
843                 CPak *p=new CPak;
844
845                 if (p->Open(path.c_str()))
846                         paklist.push_back(p);
847                 else
848                         delete p;
849         }
850         closedir (dir);
851 }
852 }
853
854 void CMainWnd::InitPakList()
855 {
856         gtk_label_set_text (GTK_LABEL (m_pStatusLabel[0]), "Building pk3 references");
857
858         if (g_strModPath.GetLength()>0)
859                 InitPaksInDir(g_strModPath.GetBuffer());
860
861         InitPaksInDir(g_strBasePath.GetBuffer());
862
863         gtk_label_set_text (GTK_LABEL (m_pStatusLabel[0]), "Ready ...");
864 }
865
866 void CMainWnd::FreePakList()
867 {
868         std::list<CPak*>::iterator i;
869
870         for ( i = paklist.begin() ; i != paklist.end() ; i++)
871         {
872                 CPak *p=*i;
873                 delete p;
874         }
875
876         paklist.clear();
877 }
878
879 void CMainWnd::DeleteTempFiles()
880 {
881         std::list<std::string>::iterator i;
882
883         for ( i = temp_files.begin() ; i != temp_files.end() ; i++)
884         {
885                 std::string path=*i;
886
887                 remove(path.c_str());
888         }
889
890         temp_files.clear();
891 }
892
893 bool CMainWnd::IsInTexList(const char *tex)
894 {
895         for ( std::list<std::string>::const_iterator i = texlist.begin() ; i != texlist.end() ; i++)
896         {
897                 std::string str=*i;
898
899                 if (str.compare(tex)==0)
900                         return TRUE;
901         }
902
903         return FALSE;
904 }
905
906 void CMainWnd::SkipLines(FILE *fp, int n)
907 {
908         for (int c=0 ; c<n ; c++)
909                 std::string line=GetLine(fp);
910 }
911
912 std::string CMainWnd::GetLine(FILE *fp)
913 {
914         std::string line;
915         char c='0';
916
917         // grab a line;
918         do
919         {
920                 fread(&c,1,1,fp);
921
922                 if (c!='\n' && c!='\t' && c!='\r')
923                         line+=c;
924
925         } while (c!='\n' && !feof(fp));
926
927         return line;
928
929 }
930
931 std::string CMainWnd::TrimString(const char *str)
932 {
933         std::string out;
934
935         int c=0;
936         while (str[c]==' ' || str[c]=='\t')
937                 c++;
938
939         int e=strlen(str);
940         while (str[e]==' ' || str[e]=='\n' || str[e]=='\r')
941                 e--;
942
943         out=str;
944         out=out.substr(c,-1);
945
946         return out;
947 }
948
949 void CMainWnd::ParseShader(const char *pathname, const char *tex)
950 {
951         if (pathname==NULL || tex==NULL)
952                 return;
953
954         char* shaderbuff;
955         int len = g_FuncTable.m_pfnLoadFile(pathname, (void**)&shaderbuff);
956
957         if (len==0)
958                 return;
959
960         std::string shader=shaderbuff;
961
962         // skip to start of shader
963         long pos=shader.find(tex);
964
965         if (pos==-1)    // shader not found????
966                 return;
967
968         shader=shader.substr(pos);
969
970         bool inStage=FALSE;
971         bool inShader=FALSE;
972
973         // step through the lines
974         while(1)
975         {
976                 pos=shader.find_first_of('\n');
977                 if (pos==-1)
978                         break;
979
980                 std::string line=shader.substr(0,pos-1);
981                 shader=shader.substr(pos+1,-1);
982
983                 line=TrimString(line.c_str());
984
985                 if (line=="")
986                         continue;
987
988                 if (line[0]=='/' && line[1]=='/')
989                         continue;
990
991                 if (line[0]=='}')
992                 {
993                         if (!inStage)
994                                 break;
995                         else
996                                 inStage=FALSE;
997
998                         continue;
999                 }
1000
1001                 if (line[0]=='{')
1002                 {
1003                         if (!inShader)
1004                         {
1005                                 inShader=TRUE;
1006                         }
1007                         else if (inShader)
1008                         {
1009                                 inStage=TRUE;
1010                         }
1011
1012                         continue;
1013                 }
1014
1015                 // check for map/animmap e.t.c;
1016
1017                 if (inStage)
1018                 {
1019
1020                         if (line.substr(0,3).compare("map")==0)
1021                         {
1022                                 std::string map=line.substr(4,-1);
1023                                 AddToTexList(map.c_str());
1024                                 continue;
1025                         }
1026
1027                         if (line.substr(0,8).compare("skyparms")==0)
1028                         {
1029                                 std::string map=line.substr(9,-1);
1030                                 AddToTexList(map.c_str());
1031                                 continue;
1032                         }
1033
1034                         if (line.substr(0,8).compare("clampmap")==0)
1035                         {
1036                                 std::string map=line.substr(9,-1);
1037                                 AddToTexList(map.c_str());
1038                                 continue;
1039                         }
1040
1041                         if (line.substr(0,7).compare("animmap")==0)
1042                         {
1043                                 std::string map=line.substr(9,-1);
1044                                 map=TrimString(map.c_str());
1045
1046                                 // skip past numbers
1047                                 long p=map.find_first_of(' ');
1048                                 map=map.substr(p+1,-1);
1049
1050                                 while (1)
1051                                 {
1052                                         long pos=map.find_first_of(' ');
1053
1054                                         if (pos==-1)
1055                                         {
1056                                                 AddToTexList(map.c_str());
1057                                                 break;
1058                                         }
1059
1060                                         std::string tex=map.substr(0,pos);
1061                                         AddToTexList(tex.c_str());
1062
1063                                         map=map.substr(pos+1,-1);
1064                                 }
1065                         }
1066                 }
1067         }
1068 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491
1069 g_free(shaderbuff);
1070 }
1071
1072 bool CMainWnd::ProcessFile(const char *nm,const char *suffix,const char *folder)
1073 {
1074         std::string name=nm;
1075         name=name.substr(0,name.length()-4);
1076         name+=suffix;
1077
1078         std::string path;
1079
1080         if (g_strModPath.GetLength()>0)
1081                 path=g_strModPath.GetBuffer();
1082         else
1083                 path=g_strBasePath.GetBuffer();
1084
1085         path+=folder;
1086         path+="/";
1087         path+=name;
1088
1089         std::string rpath=folder;
1090         rpath+="/";
1091         rpath+=name;
1092
1093         if (IsExcluded(rpath.c_str()))  // quit out with a FALSE so we try others
1094                 return FALSE;
1095
1096         FILE *fp;
1097         fp=fopen(path.c_str(),"rb");
1098
1099         if (fp)
1100         {
1101                 if (!pak.IsInPak(rpath.c_str()))
1102                 {
1103                         m_Tree.AddPath(rpath.c_str());
1104                         pak.AddExternalFile(rpath.c_str(),path.c_str());
1105                 }
1106
1107                 fclose(fp);
1108                 return TRUE;
1109         }
1110         else
1111                 return FindInAPk3(rpath.c_str());
1112
1113
1114         return FALSE;
1115 }
1116
1117 bool CMainWnd::ProcessFile(const char *nm)
1118 {
1119         std::string name=nm;
1120
1121         if (IsExcluded(name.c_str()))   // quit out with a TRUE so we think it was added
1122                 return TRUE;
1123
1124         std::string path;
1125
1126         if (g_strModPath.GetLength()>0)
1127                 path=g_strModPath.GetBuffer();
1128         else
1129                 path=g_strBasePath.GetBuffer();
1130
1131         path+=name;
1132
1133         FILE *fp;
1134         fp=fopen(path.c_str(),"rb");
1135
1136         if (fp)
1137         {
1138                 if (!pak.IsInPak(name.c_str()))
1139                 {
1140                         m_Tree.AddPath(name.c_str());
1141                         pak.AddExternalFile(name.c_str(),path.c_str());
1142                 }
1143
1144                 return TRUE;
1145         }
1146         else
1147         {
1148                 return FindInAPk3(name.c_str());
1149         }
1150
1151
1152         return FALSE;
1153 }
1154
1155 bool CMainWnd::FindInAPk3(const char *name)
1156 {
1157         std::list<CPak*>::iterator i;
1158
1159         for ( i = paklist.begin() ; i != paklist.end() ; i++)
1160         {
1161                 CPak *p=*i;
1162
1163                 if (p->m_filename.CompareNoCase(pak.m_filename)==0)
1164                         continue;
1165
1166                 std::string fname=p->m_filename.GetBuffer();
1167                 long pos=fname.find_last_of('/');
1168                 fname=fname.substr(pos+1,-1);
1169
1170                 if (IsExcluded(fname.c_str()))
1171                         continue;
1172
1173                 if (p->IsInPak(name))
1174                 {
1175                         pak_entry pe=p->FindPE(name);
1176                         m_Tree.AddPath(name);
1177                         pak.AddPakFile(name,p->m_filename.GetBuffer(),pe.compressed,pe.uncompressed);
1178                         return TRUE;
1179                 }
1180         }
1181         return FALSE;
1182 }
1183
1184 void CMainWnd::OnAdd()
1185 {
1186         std::string path;
1187         if (g_strModPath.GetLength()>0)
1188                 path=g_strModPath.GetBuffer();
1189         else
1190                 path=g_strBasePath.GetBuffer();
1191
1192         //char *filename=file_dialog(TRUE,"Choose a file...",path.c_str(),"*.*");
1193         gchar *filename=g_FuncTable.m_pfnFileDialog(m_pMainWnd,TRUE,"Choose a file...",path.c_str(),"pk3man");
1194
1195         if (filename==NULL)
1196                 return;
1197
1198         int c=0;
1199
1200         while (filename[c]!='\0')
1201         {
1202                 if (filename[c]=='\\')
1203                         filename[c]='/';
1204
1205                 c++;
1206         }
1207
1208         std::string fname=filename;
1209
1210         long p=path.length();
1211         fname=fname.substr(p,-1);
1212
1213         if (pak.IsInPak((char*)fname.c_str()))
1214                 return;
1215
1216         pak.AddExternalFile((char *)fname.c_str(),(char *)filename);
1217         m_Tree.AddPath((char *)fname.c_str());
1218
1219 }
1220
1221 void CMainWnd::OnDelete()
1222 {
1223         std::string path=m_Tree.GetSelected();
1224
1225         if (path=="")
1226                 return;
1227
1228         pak.Delete(path.c_str());
1229
1230         //m_Tree.RemovePath(path.c_str());
1231
1232         // dodgy hack but works for now
1233         m_Tree.Clear();
1234         UpdateTree();
1235
1236 }
1237
1238 void CMainWnd::OnRename()
1239 {
1240         std::string path=m_Tree.GetSelected();
1241
1242         if (path=="")
1243                 return;
1244
1245         CRenameDlg dlg;
1246         dlg.m_Name=path;
1247
1248         if (dlg.DoModal()==IDOK)
1249         {
1250                 pak.Rename(path.c_str(),dlg.m_Name.c_str());
1251                 m_Tree.Clear();
1252                 UpdateTree();
1253         }
1254
1255 }
1256
1257 void CMainWnd::UpdateTree()
1258 {
1259         // clear the tree and fill it with the items in the pak
1260
1261         for ( std::list<pak_entry>::const_iterator iEntry = pak.entries.begin() ; iEntry != pak.entries.end() ; iEntry++)
1262         {
1263                 pak_entry pe=*iEntry;
1264
1265                 std::string name;
1266                 if (pe.rename)
1267                         name=pe.newname;
1268                 else
1269                         name=pe.filename;
1270
1271                 m_Tree.AddPath(name.c_str());
1272         }
1273
1274 }
1275
1276 void CMainWnd::OnExtract()
1277 {
1278         std::string path=m_Tree.GetSelected();
1279
1280         if (path=="")
1281                 return;
1282
1283         pak_entry pe=pak.FindPE((char*)path.c_str());
1284
1285         std::string bpath;
1286         if (g_strModPath.GetLength()>0)
1287                 bpath=g_strModPath.GetBuffer();
1288         else
1289                 bpath=g_strBasePath.GetBuffer();
1290
1291                 //char *pathto=dir_dialog("Extract to ...",bpath.c_str());
1292         gchar *pathto=g_FuncTable.m_pfnDirDialog(m_pMainWnd,"Extract to...",bpath.c_str());
1293
1294         if (pathto==NULL)
1295                 return;
1296
1297         long pos=path.find_last_of('/');
1298         std::string name=path.substr(pos+1);
1299
1300         std::string cpath=pathto;
1301         cpath+=name;
1302
1303         if (pe.pakname.compare(pak.m_filename.GetBuffer())==0)
1304         {
1305                 // its in pak
1306                 pak.ExtractTo((char*)path.c_str(),(char*)cpath.c_str());
1307                 return;
1308         }
1309
1310 }
1311
1312 void CMainWnd::OnView()
1313 {
1314         std::string path=m_Tree.GetSelected();
1315
1316         if (path=="")
1317                 return;
1318
1319         pak_entry pe=pak.FindPE(path.c_str());
1320
1321         long p=pe.filename.find_last_of('/');
1322         std::string name=pe.filename.substr(p+1,-1);
1323         std::string temppath=g_strTempPath.GetBuffer()+name;
1324
1325         if (pe.frompak && pe.pakname.compare(pak.m_filename.GetBuffer())==0)
1326         {
1327                 // its in pak
1328                 if (!pak.ExtractTo(path.c_str(),(char *)temppath.c_str()))
1329                         return;
1330
1331                 temp_files.push_back(temppath);
1332
1333                 // view it
1334         #ifdef WIN32
1335                 HANDLE hInst=ShellExecute(NULL,"open",(LPCTSTR)temppath.c_str(),NULL,NULL,SW_SHOWNORMAL);
1336         #endif
1337
1338                 return;
1339         }
1340
1341         if (!pe.frompak)
1342         {
1343 #ifdef WIN32
1344                 HANDLE hInst=ShellExecute(NULL,"open",(LPCTSTR)pe.pathname.c_str(),NULL,NULL,SW_SHOWNORMAL);
1345 #endif
1346                 return;
1347         }
1348
1349         if (pe.frompak)
1350         {
1351                 CPak p;
1352                 if (!p.Open(pe.pakname.c_str()))
1353                         return;
1354
1355                 if (!p.ExtractTo(path.c_str(),(char *)temppath.c_str()))
1356                         return;
1357
1358                 temp_files.push_back(temppath);
1359
1360                 // view it
1361 #ifdef WIN32
1362                 HANDLE hInst=ShellExecute(NULL,"open",(LPCTSTR)temppath.c_str(),NULL,NULL,SW_SHOWNORMAL);
1363 #endif
1364                 return;
1365         }
1366 }
1367
1368 #ifdef WIN32
1369 void ShortToLong(CString &thePath)
1370 {
1371         WIN32_FIND_DATA wfd;
1372         std::string spath=thePath.GetBuffer();
1373         std::string lpath="";
1374         while(1)
1375         {
1376                 FindFirstFile(spath.c_str(),&wfd);
1377                 std::string fname=wfd.cFileName;
1378                 lpath=fname+"\\"+lpath;
1379                 long pos=spath.find_last_of('\\');
1380                 spath=spath.substr(0,pos);
1381                 pos=spath.find_last_of('\\');
1382
1383                 if (pos==-1)
1384                 {
1385                         lpath=spath+"\\"+lpath;
1386                         break;
1387                 }
1388         }
1389         thePath=lpath.c_str();
1390 }
1391 #endif
1392
1393 void CMainWnd::GetPaths()
1394 {
1395 #if 0 //mattn
1396 #ifdef WIN32
1397
1398         // convert it to long format
1399         ShortToLong(g_strBasePath);
1400
1401         // mod path
1402         if (strcmp(mode,"Quake III Team Arena")==0)
1403         {
1404                 g_strModPath=g_strBasePath;
1405                 long p=g_strModPath.Find("\\baseq3");
1406                 g_strModPath=g_strModPath.Left(p);
1407                 g_strModPath+="\\missionpack\\";
1408
1409                 g_FuncTable.m_pfnQE_ConvertDOSToUnixName ((char *)g_strModPath.GetBuffer(), g_strModPath.GetBuffer());
1410         }
1411
1412         g_FuncTable.m_pfnQE_ConvertDOSToUnixName ((char *)g_strBasePath.GetBuffer(), g_strBasePath.GetBuffer());
1413
1414         // apppath
1415         // get path to the editor
1416         char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1);
1417         GetModuleFileName(NULL, pBuffer, _MAX_PATH);
1418         pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0';
1419         g_strAppPath.ReleaseBuffer();
1420         g_FuncTable.m_pfnQE_ConvertDOSToUnixName ((char *)g_strAppPath.GetBuffer(), g_strAppPath.GetBuffer());
1421
1422         char temp_path[_MAX_PATH];
1423         GetTempPath(_MAX_PATH,temp_path);
1424         g_strTempPath=temp_path;
1425
1426 #endif
1427
1428 #ifdef __linux__
1429         Str tmp;
1430         tmp = g_strBasePath.GetBuffer();
1431         tmp += "/../";
1432
1433         // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32)
1434         // it's a general convention in Radiant to have the slash at the end of directories
1435         char real[PATH_MAX];
1436         realpath (tmp.GetBuffer(), real);
1437         if (real[strlen(real)-1] != '/')
1438         strcat(real, "/");
1439         g_strAppPath = real;
1440
1441         g_strTempPath="~/.tmp";
1442 #endif
1443
1444         extern const char *PLUGIN_NAME;
1445         g_strBitmapsPath = g_FuncTable.m_pfnPathForPluginName(PLUGIN_NAME);
1446         g_strBitmapsPath += "bitmaps/";
1447 #endif
1448 }
1449
1450 void CMainWnd::UpdateStatus()
1451 {
1452         std::string path=m_Tree.GetSelected();
1453
1454         if (path=="")
1455         {
1456                 gtk_label_set_text (GTK_LABEL (m_pStatusLabel[0]), "");
1457                 gtk_label_set_text (GTK_LABEL (m_pStatusLabel[1]), "");
1458                 gtk_label_set_text (GTK_LABEL (m_pStatusLabel[2]), "");
1459
1460                 return;
1461         }
1462
1463         pak_entry pe=pak.FindPE(path.c_str());
1464
1465         std::string p=path;
1466         long pos=p.find_last_of('/');
1467         p=p.substr(pos+1);
1468         gtk_label_set_text (GTK_LABEL (m_pStatusLabel[0]), p.c_str());
1469
1470         char lbl[255];
1471         sprintf(lbl," %ldk ",pe.uncompressed/1000);
1472         gtk_label_set_text (GTK_LABEL (m_pStatusLabel[1]), lbl);
1473
1474         sprintf(lbl," %ldk ",pe.compressed/1000);
1475         gtk_label_set_text (GTK_LABEL (m_pStatusLabel[2]), lbl);
1476
1477 }
1478
1479 void CMainWnd::HandleDrop()
1480 {
1481         std::string path=m_Tree.GetSelected();
1482         bool file_selected=TRUE;
1483
1484         if (path=="")
1485                 file_selected=FALSE;
1486
1487         //if (m_mnuDrop == NULL) // first time, load it up
1488         //{
1489                 GtkAccelGroup *accel;//, *menu_in_menu_accel;
1490                 GtkWidget *menu;//, *menu_in_menu, *item, *submenu;
1491
1492                 menu = m_mnuDrop = gtk_menu_new ();
1493                 accel = gtk_accel_group_new ();
1494                 gtk_menu_set_accel_group (GTK_MENU (menu), accel);
1495
1496                 //menu_in_menu = create_menu_in_menu (menu, "Select", accel, &menu_in_menu_accel);
1497
1498                 create_menu_item (menu, "Add file", accel,
1499                         GTK_SIGNAL_FUNC (HandleCommand), ID_ADD);
1500
1501                 if (file_selected)
1502                 {
1503                         create_menu_item (menu, "View File", accel,
1504                         GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW);
1505
1506                         create_menu_item (menu, "Extract file", accel,
1507                         GTK_SIGNAL_FUNC (HandleCommand), ID_EXTRACT);
1508
1509                         menu_separator (menu);
1510
1511                         create_menu_item (menu, "Rename File", accel,
1512                         GTK_SIGNAL_FUNC (HandleCommand), ID_RENAME);
1513
1514                         create_menu_item (menu, "Delete file", accel,
1515                         GTK_SIGNAL_FUNC (HandleCommand), ID_DELETE);
1516                 }
1517         //}
1518
1519         gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME);
1520 }
1521
1522
1523 ////////////////////////////////////////////
1524 // some handy stuff ripped from GtkRadiant
1525 ////////////////////////////////////////////
1526
1527
1528 GtkWidget* create_menu_in_menu (GtkWidget *menu, gchar *label, GtkAccelGroup *menu_accel,
1529                                 GtkAccelGroup **submenu_accel)
1530 {
1531         GtkWidget *item, *submenu;
1532         guint tmp_key;
1533
1534         item = gtk_menu_item_new_with_label ("");
1535         tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (item)->child), label);
1536         gtk_widget_add_accelerator (item, "activate_item", menu_accel, tmp_key, 0, (GtkAccelFlags)0);
1537         gtk_widget_show (item);
1538         gtk_container_add (GTK_CONTAINER (menu), item);
1539
1540         submenu = gtk_menu_new ();
1541         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
1542         *submenu_accel = gtk_accel_group_new ();
1543         gtk_menu_set_accel_group (GTK_MENU (submenu), *submenu_accel);
1544
1545         return submenu;
1546 }
1547
1548 GtkWidget* create_menu_item (GtkWidget *menu, gchar *label, GtkAccelGroup *menu_accel,
1549                                 GtkSignalFunc func, int id)
1550 {
1551         GtkWidget *item;
1552         guint tmp_key;
1553
1554 #ifdef NO_UNDERSCORE
1555         char label_tmp[1024];
1556         strcpy( label_tmp, label );
1557         if (char* c = strchr (label_tmp, '_'))
1558                 while (*c)
1559                 *c++ = *(c+1);
1560         item = gtk_menu_item_new_with_label (label_tmp);
1561 #else
1562         item = gtk_menu_item_new_with_label ("");
1563         tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (item)->child), label);
1564         gtk_widget_add_accelerator (item, "activate_item", menu_accel, tmp_key, 0, (GtkAccelFlags)0);
1565 #endif
1566         gtk_widget_show (item);
1567         gtk_container_add (GTK_CONTAINER (menu), item);
1568         gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
1569
1570
1571         return item;
1572 }
1573
1574 GtkWidget* menu_separator (GtkWidget *menu)
1575 {
1576         GtkWidget *menu_item = gtk_menu_item_new ();
1577         gtk_menu_append (GTK_MENU (menu), menu_item);
1578         gtk_widget_set_sensitive (menu_item, FALSE);
1579         gtk_widget_show (menu_item);
1580         return menu_item;
1581 }