]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - misc/source/fteqcc-src/qccgui.c
Update fteqcc source
[voretournament/voretournament.git] / misc / source / fteqcc-src / qccgui.c
1 #include <windows.h>
2 #include <windowsx.h>
3 #include <commctrl.h>
4 #include <commdlg.h>
5 #include <richedit.h>
6 #include <stdio.h>
7 #include <sys/stat.h>
8
9 #include "qcc.h"
10 #include "gui.h"
11
12
13 /*
14 ==============
15 LoadFile
16 ==============
17 */
18 unsigned char *QCC_ReadFile (const char *fname, void *buffer, int len)
19 {
20         long    length;
21         FILE *f;
22         f = fopen(fname, "rb");
23         if (!f)
24                 return NULL;
25         length = fread(buffer, 1, len, f);
26         fclose(f);
27
28         if (length != len)
29                 return NULL;
30
31         return buffer;
32 }
33 int QCC_FileSize (const char *fname)
34 {
35         long    length;
36         FILE *f;
37         f = fopen(fname, "rb");
38         if (!f)
39                 return -1;
40         fseek(f, 0, SEEK_END);
41         length = ftell(f);
42         fclose(f);
43
44         return length;
45 }
46
47 pbool QCC_WriteFile (const char *name, void *data, int len)
48 {
49         long    length;
50         FILE *f;
51         f = fopen(name, "wb");
52         if (!f)
53                 return false;
54         length = fwrite(data, 1, len, f);
55         fclose(f);
56
57         if (length != len)
58                 return false;
59
60         return true;
61 }
62
63 #undef printf
64 #undef Sys_Error
65
66 void Sys_Error(const char *text, ...)
67 {
68         va_list argptr;
69         static char msg[2048];  
70
71         va_start (argptr,text);
72         QC_vsnprintf (msg,sizeof(msg)-1, text,argptr);
73         va_end (argptr);
74
75         QCC_Error(ERR_INTERNAL, "%s", msg);
76 }
77
78
79 FILE *logfile;
80 int logprintf(const char *format, ...)
81 {
82         va_list         argptr;
83         static char             string[1024];
84
85         va_start (argptr, format);
86 #ifdef _WIN32
87         _vsnprintf (string,sizeof(string)-1, format,argptr);
88 #else
89         vsnprintf (string,sizeof(string), format,argptr);
90 #endif
91         va_end (argptr);
92
93         printf("%s", string);
94         if (logfile)
95                 fputs(string, logfile);
96
97         return 0;
98 }
99
100
101
102
103
104
105
106
107
108
109
110 #define Edit_Redo(hwndCtl)                      ((BOOL)(DWORD)SNDMSG((hwndCtl), EM_REDO, 0L, 0L))
111
112
113 #define MAIN_WINDOW_CLASS_NAME "FTEMAINWINDOW"
114 #define MDI_WINDOW_CLASS_NAME "FTEMDIWINDOW"
115 #define EDIT_WINDOW_CLASS_NAME "FTEEDITWINDOW"
116 #define OPTIONS_WINDOW_CLASS_NAME "FTEOPTIONSWINDOW"
117
118 #define EM_GETSCROLLPOS  (WM_USER + 221)
119 #define EM_SETSCROLLPOS  (WM_USER + 222)
120
121
122
123 int GUIprintf(const char *msg, ...);
124 void GUIPrint(HWND wnd, char *msg);
125
126 char finddef[256];
127
128 void RunCompiler(char *args);
129
130 HINSTANCE ghInstance;
131 HMODULE richedit;
132
133 pbool resetprogssrc;    //progs.src was changed, reload project info.
134
135
136 HWND mainwindow;
137 HWND mdibox;
138 HWND outputwindow;
139 HWND outputbox;
140 HWND projecttree;
141 HWND gotodefbox;
142 HWND gotodefaccept;
143
144 FILE *logfile;
145
146 struct{
147         char *text;
148         HWND hwnd;
149         int washit;
150 } buttons[] = {
151         {"Compile"},
152         {"Edit"},
153         {"Options"},
154         {"Quit"}
155 };
156
157 #define ID_COMPILE      0
158 #define ID_EDIT 1
159 #define ID_OPTIONS 2
160 #define ID_QUIT 3
161
162 #define NUMBUTTONS sizeof(buttons)/sizeof(buttons[0])
163
164
165
166 void GUI_DialogPrint(char *title, char *text)
167 {
168         MessageBox(mainwindow, text, title, 0);
169 }
170
171 HWND CreateAnEditControl(HWND parent)
172 {
173         HWND newc;
174
175         if (!richedit)
176                 richedit = LoadLibrary("RICHED32.DLL");
177
178         newc=CreateWindowEx(WS_EX_CLIENTEDGE,
179                 richedit?RICHEDIT_CLASS:"EDIT",
180                 "",
181                 WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | 
182                 WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
183                 ES_MULTILINE | ES_AUTOVSCROLL,
184                 0, 0, 0, 0,
185                 parent,
186                 NULL,
187                 ghInstance,
188                 NULL);
189
190         if (!newc)
191                 newc=CreateWindowEx(WS_EX_CLIENTEDGE,
192                         richedit?RICHEDIT_CLASS10A:"EDIT",      //fall back to the earlier version
193                         "",
194                         WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | 
195                         WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
196                         ES_MULTILINE | ES_AUTOVSCROLL,
197                         0, 0, 0, 0,
198                         parent,
199                         NULL,
200                         ghInstance,
201                         NULL);
202
203         if (!newc)
204         {       //you've not got RICHEDIT installed properly, I guess
205                 FreeLibrary(richedit);
206                 richedit = NULL;
207                 newc=CreateWindowEx(WS_EX_CLIENTEDGE,
208                         "EDIT",
209                         "",
210                         WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | 
211                         WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
212                         ES_MULTILINE | ES_AUTOVSCROLL,
213                         0, 0, 0, 0,
214                         parent,
215                         NULL,
216                         ghInstance,
217                         NULL);
218         }
219
220         //go to lucidia console, 10pt
221         {
222                 CHARFORMAT cf;
223                 memset(&cf, 0, sizeof(cf));
224                 cf.cbSize = sizeof(cf);
225                 cf.dwMask = CFM_BOLD | CFM_FACE;// | CFM_SIZE;
226                 strcpy(cf.szFaceName, "Lucida Console");
227                 cf.yHeight = 5;
228
229                 SendMessage(newc, EM_SETCHARFORMAT, SCF_ALL, (WPARAM)&cf);
230         }
231
232         if (richedit)
233         {
234                 SendMessage(newc, EM_EXLIMITTEXT, 0, 1<<20);
235         }
236
237         ShowWindow(newc, SW_SHOW);
238
239         return newc;
240 }
241
242
243
244
245 enum {
246         IDM_OPENDOCU=32,
247         IDM_OPENNEW,
248         IDM_GOTODEF,
249         IDM_SAVE,
250         IDM_FIND,
251         IDM_QUIT,
252         IDM_UNDO,
253         IDM_REDO,
254         IDM_ABOUT,
255         IDM_HIGHTLIGHT,
256         IDM_CASCADE,
257         IDM_TILE_HORIZ,
258         IDM_TILE_VERT,
259
260         IDI_O_LEVEL0,
261         IDI_O_LEVEL1,
262         IDI_O_LEVEL2,
263         IDI_O_LEVEL3,
264         IDI_O_DEFAULT,
265         IDI_O_DEBUG,
266         IDI_O_CHANGE_PROGS_SRC,
267         IDI_O_ADDITIONALPARAMETERS,
268         IDI_O_OPTIMISATION,
269         IDI_O_COMPILER_FLAG,
270         IDI_O_USE,
271         IDI_O_APPLY,
272         IDI_O_TARGET,
273         IDI_O_SYNTAX_HIGHLIGHTING,
274
275         IDM_FIRSTCHILD
276 };
277
278
279 typedef struct editor_s {
280         char filename[MAX_PATH];        //abs
281         HWND window;
282         HWND editpane;
283         pbool modified;
284         time_t filemodifiedtime;
285         struct editor_s *next;
286 } editor_t;
287
288 editor_t *editors;
289
290 void EditorReload(editor_t *editor);
291 int EditorSave(editor_t *edit);
292 void EditFile(char *name, int line);
293 pbool EditorModified(editor_t *e);
294 int Rehighlight(editor_t *edit);
295
296 void QueryOpenFile(void)
297 {
298         char filename[MAX_PATH];
299         char oldpath[MAX_PATH+10];
300         OPENFILENAME ofn;
301         memset(&ofn, 0, sizeof(ofn));
302         ofn.lStructSize = sizeof(ofn);
303         ofn.hInstance = ghInstance;
304         ofn.lpstrFile = filename;
305         ofn.nMaxFile = sizeof(filename)-1;
306         memset(filename, 0, sizeof(filename));
307         GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
308         if (GetOpenFileName(&ofn))
309                 EditFile(filename, -1);
310         SetCurrentDirectory(oldpath);
311 }
312
313 //IDM_ stuff that needs no active menu
314 void GenericMenu(WPARAM wParam)
315 {
316         switch(LOWORD(wParam))
317         {
318         case IDM_OPENNEW:
319                 QueryOpenFile();
320                 break;
321
322         case IDM_ABOUT:
323                 MessageBox(NULL, "FTE QuakeC Compiler\nWritten by Forethough Entertainment.\n\nIt has a few cool features, like a semi-useful IDE.\n\nSupports:\nPrecompiler (with macros)\nArrays\n+= / -= / *= / /= operations.\nSwitch statements\nfor loops\nLots of optimisations.", "About", 0);
324                 break;
325
326         case IDM_CASCADE:
327                 SendMessage(mdibox, WM_MDICASCADE, 0, 0);
328                 break;
329         case IDM_TILE_HORIZ:
330                 SendMessage(mdibox, WM_MDITILE, MDITILE_HORIZONTAL, 0);
331                 break;
332         case IDM_TILE_VERT:
333                 SendMessage(mdibox, WM_MDITILE, MDITILE_VERTICAL, 0);
334                 break;
335         }
336 }
337
338 void EditorMenu(editor_t *editor, WPARAM wParam)
339 {
340         switch(LOWORD(wParam))
341         {
342         case IDM_OPENDOCU:
343                 {
344                         char buffer[1024];
345                         int total;
346                         total = SendMessage(editor->editpane, EM_GETSELTEXT, (WPARAM)sizeof(buffer)-1, (LPARAM)buffer);
347                         buffer[total]='\0';
348                         if (!total)
349                         {
350                                 MessageBox(NULL, "There is no name currently selected.", "Whoops", 0);
351                                 break;
352                         }
353                         else
354                                 EditFile(buffer, -1);
355                 }
356                 break;
357         case IDM_SAVE:
358                 EditorSave(editor);
359                 break;
360         case IDM_GOTODEF:
361                 {
362                         char buffer[1024];
363                         int total;
364                         total = SendMessage(editor->editpane, EM_GETSELTEXT, (WPARAM)sizeof(buffer)-1, (LPARAM)buffer);
365                         buffer[total]='\0';
366                         if (!total)
367                         {
368                                 MessageBox(NULL, "There is no name currently selected.", "Whoops", 0);
369                                 break;
370                         }
371                         else
372                                 GoToDefinition(buffer);
373                 }
374                 break;
375         case IDM_HIGHTLIGHT:
376                 Rehighlight(editor);
377                 break;
378
379         case IDM_UNDO:
380                 Edit_Undo(editor->editpane);
381                 break;
382         case IDM_REDO:
383                 Edit_Redo(editor->editpane);
384                 break;
385
386         default:
387                 GenericMenu(wParam);
388                 break;
389         }
390 }
391
392 static LONG CALLBACK EditorWndProc(HWND hWnd,UINT message,
393                                      WPARAM wParam,LPARAM lParam)
394 {
395         RECT rect;
396         HDC hdc;
397         PAINTSTRUCT ps;
398
399         editor_t *editor;
400         for (editor = editors; editor; editor = editor->next)
401         {
402                 if (editor->window == hWnd)
403                         break;
404                 if (editor->window == NULL)
405                         break;  //we're actually creating it now.
406         }
407         if (!editor)
408                 goto gdefault;
409
410         switch (message)
411         {
412         case WM_CLOSE:
413         case WM_QUIT:
414                 if (editor->modified)
415                 {
416                         switch (MessageBox(hWnd, "Would you like to save?", editor->filename, MB_YESNOCANCEL))
417                         {
418                         case IDCANCEL:
419                                 return false;
420                         case IDYES:
421                                 if (!EditorSave(editor))
422                                         return false;
423                         case IDNO:
424                         default:
425                                 break;
426                         }
427                 }
428                 goto gdefault;
429         case WM_DESTROY:
430                 {
431                         editor_t *e;
432                         if (editor == editors)
433                         {
434                                 editors = editor->next;
435                                 free(editor);
436                                 return 0;
437                         }
438                         for (e = editors; e; e = e->next)
439                         {
440                                 if (e->next == editor)
441                                 {
442                                         e->next = editor->next;
443                                         free(editor);
444                                         return 0;
445                                 }
446                         }
447                         MessageBox(0, "Couldn't destroy file reference", "WARNING", 0);
448                 }
449                 goto gdefault;
450         case WM_CREATE:
451                 editor->editpane = CreateAnEditControl(hWnd);
452                 /*
453                 editor->editpane=CreateWindowEx(WS_EX_CLIENTEDGE,
454                         richedit?RICHEDIT_CLASS:"EDIT",
455                         "",
456                         WS_CHILD  | WS_VISIBLE | 
457                         WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
458                         ES_MULTILINE | ES_AUTOVSCROLL,
459                         0, 0, 0, 0,
460                         hWnd,
461                         NULL,
462                         ghInstance,
463                         NULL);
464 */
465                 if (richedit)
466                 {
467                         SendMessage(editor->editpane, EM_EXLIMITTEXT, 0, 1<<31);
468
469                         SendMessage(editor->editpane, EM_SETUNDOLIMIT, 256, 256);
470                 }
471                 goto gdefault;
472         case WM_SIZE:
473                 GetClientRect(hWnd, &rect);
474                 SetWindowPos(editor->editpane, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0);
475                 goto gdefault;
476         case WM_PAINT:
477                 hdc=BeginPaint(hWnd,(LPPAINTSTRUCT)&ps);
478
479                 EndPaint(hWnd,(LPPAINTSTRUCT)&ps);
480                 return TRUE;
481                 break;
482         case WM_COMMAND:
483                 if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == editor->editpane)
484                 {
485                         if (!editor->modified)
486                         {
487                                 char title[2048];
488                                 CHARRANGE chrg;
489
490                                 editor->modified = true;
491                                 if (EditorModified(editor))
492                                         if (MessageBox(NULL, "warning: file was modified externally. reload?", "Modified!", MB_YESNO) == IDYES)
493                                                 EditorReload(editor);
494
495
496                                 SendMessage(editor->editpane, EM_EXGETSEL, 0, (LPARAM) &chrg);
497                                 if (editor->modified)
498                                         sprintf(title, "*%s:%i - FTEQCC Editor", editor->filename, 1+Edit_LineFromChar(editor->editpane, chrg.cpMin));
499                                 else
500                                         sprintf(title, "%s:%i - FTEQCC Editor", editor->filename, 1+Edit_LineFromChar(editor->editpane, chrg.cpMin));
501                                 SetWindowText(editor->window, title);
502                         }
503                 }
504                 else
505                 {
506                         if (mdibox)
507                                 goto gdefault;
508                         EditorMenu(editor, wParam);
509                 }
510                 break;
511         case WM_NOTIFY:
512                 {
513                     NMHDR *nmhdr;
514                         SELCHANGE *sel;
515                         char title[2048];
516                         nmhdr = (NMHDR *)lParam;
517                         switch(nmhdr->code)
518                         {
519                         case EN_SELCHANGE:
520                                 sel = (SELCHANGE *)nmhdr;
521                                 if (editor->modified)
522                                         sprintf(title, "*%s:%i - FTEQCC Editor", editor->filename, 1+Edit_LineFromChar(editor->editpane, sel->chrg.cpMin));
523                                 else
524                                         sprintf(title, "%s:%i - FTEQCC Editor", editor->filename, 1+Edit_LineFromChar(editor->editpane, sel->chrg.cpMin));
525                                 SetWindowText(editor->window, title);
526                                 break;
527                         }
528                 }
529         default:
530         gdefault:
531                 if (mdibox)
532                         return DefMDIChildProc(hWnd,message,wParam,lParam);
533                 else
534                         return DefWindowProc(hWnd,message,wParam,lParam);
535         }
536         return 0;
537 }
538
539 #if 1
540 static DWORD lastcolour;
541 int GUIEmitText(HWND wnd, int start, char *text, int len)
542 {
543         int c, cr;
544         DWORD colour;
545         CHARFORMAT cf;
546
547         if (!len)
548                 return start;
549
550         c = text[len];
551         text[len] = '\0';
552         Edit_SetSel(wnd,start,start);
553         Edit_ReplaceSel(wnd,text);
554
555         if (!strcmp(text, "void"))
556                 colour = RGB(0, 0, 255);
557         else if (!strcmp(text, "float"))
558                 colour = RGB(0, 0, 255);
559         else if (!strcmp(text, "vector"))
560                 colour = RGB(0, 0, 255);
561         else if (!strcmp(text, "entity"))
562                 colour = RGB(0, 0, 255);
563         else if (!strcmp(text, "local"))
564                 colour = RGB(0, 0, 255);
565         else if (!strcmp(text, "string"))
566                 colour = RGB(0, 0, 255);
567         else if (!strcmp(text, "struct"))
568                 colour = RGB(0, 0, 255);
569         else if (!strcmp(text, "class"))
570                 colour = RGB(0, 0, 255);
571         else if (!strcmp(text, "union"))
572                 colour = RGB(0, 0, 255);
573         else if (!strcmp(text, "const"))
574                 colour = RGB(0, 0, 255);
575         else if (!strcmp(text, "var"))
576                 colour = RGB(0, 0, 255);
577         else if (!strcmp(text, "nosave"))
578                 colour = RGB(0, 0, 255);
579
580         else if (!strcmp(text, "goto"))
581                 colour = RGB(255, 0, 0);
582         else if (!strcmp(text, "thinktime"))
583                 colour = RGB(0, 0, 255);
584         else if (!strcmp(text, "if"))
585                 colour = RGB(0, 0, 255);
586         else if (!strcmp(text, "else"))
587                 colour = RGB(0, 0, 255);
588         else if (!strcmp(text, "switch"))
589                 colour = RGB(0, 0, 255);
590         else if (!strcmp(text, "case"))
591                 colour = RGB(0, 0, 255);
592         else if (!strcmp(text, "default"))
593                 colour = RGB(0, 0, 255);
594         else if (!strcmp(text, "break"))
595                 colour = RGB(0, 0, 255);
596         else if (!strcmp(text, "continue"))
597                 colour = RGB(0, 0, 255);
598         else if (!strcmp(text, "do"))
599                 colour = RGB(0, 0, 255);
600         else if (!strcmp(text, "while"))
601                 colour = RGB(0, 0, 255);
602         else if (!strcmp(text, "for"))
603                 colour = RGB(0, 0, 255);
604         else if (!strcmp(text, "return"))
605                 colour = RGB(0, 0, 255);
606
607         else if (!strcmp(text, "self"))
608                 colour = RGB(0, 0, 127);
609         else if (!strcmp(text, "this"))
610                 colour = RGB(0, 0, 127);
611         else if (!strcmp(text, "other"))
612                 colour = RGB(0, 0, 127);
613         else if (!strcmp(text, "world"))
614                 colour = RGB(0, 0, 127);
615         else if (!strcmp(text, "time"))
616                 colour = RGB(0, 0, 127);
617
618
619         else if (!strcmp(text, "#define"))
620                 colour = RGB(0, 128, 255);
621         else if (!strcmp(text, "#ifdef"))
622                 colour = RGB(0, 128, 255);
623         else if (!strcmp(text, "#ifndef"))
624                 colour = RGB(0, 128, 255);
625         else if (!strcmp(text, "#else"))
626                 colour = RGB(0, 128, 255);
627         else if (!strcmp(text, "#endif"))
628                 colour = RGB(0, 128, 255);
629         else if (!strcmp(text, "#undef"))
630                 colour = RGB(0, 128, 255);
631         else if (!strcmp(text, "#pragma"))
632                 colour = RGB(0, 128, 255);
633         else if (!strcmp(text, "#includelist"))
634                 colour = RGB(0, 128, 255);
635         else if (!strcmp(text, "#endlist"))
636                 colour = RGB(0, 128, 255);
637
638
639         else if (*text == '\"')
640                 colour = RGB(128, 0, 0);
641
642         else if (!strncmp(text, "//", 2))
643                 colour = RGB(0, 127, 0);
644         else if (!strncmp(text, "/*", 2))
645                 colour = RGB(0, 127, 0);
646         else
647                 colour = RGB(0, 0, 0);
648
649         text[len] = c;
650
651         cr = 0;
652         for (c = 0; c < len; c++)
653                 if (text[c] == '\r')
654                         cr++;
655         if (cr)
656                 len-=cr;
657
658         if (colour == lastcolour)
659                 return start+len;
660
661         lastcolour = colour;
662
663         Edit_SetSel(wnd,start,start+len);
664         memset(&cf, 0, sizeof(cf));
665         cf.cbSize = sizeof(cf);
666         cf.dwMask = CFM_COLOR;
667         cf.crTextColor = colour;
668         SendMessage(wnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
669         Edit_SetSel(wnd,start+len,start+len);
670
671         return start + len;
672 }
673 void GUIFormattingPrint(HWND wnd, char *msg)
674 {
675         int len=Edit_GetTextLength(wnd);
676         char *start;
677         CHARRANGE chrg;
678         lastcolour = RGB(0,0,0);
679         SendMessage(wnd, WM_SETREDRAW, false, 0);
680         chrg.cpMin = chrg.cpMax = 0;
681         SendMessage(wnd, EM_EXSETSEL, 0, (LPARAM) &chrg);
682
683         for(start = msg;;)
684         {
685                 if (!*msg)
686                         break;
687                 else if (*msg == '/' && msg[1] == '/')
688                 {
689                         len = GUIEmitText(wnd, len, start, msg - start);
690                         start = msg;
691
692                         msg+=2;
693                         while(*msg && *msg != '\n' && *msg != '\r')
694                                 msg++;
695                 }
696                 else if (*msg == '/' && msg[1] == '*')
697                 {
698                         len = GUIEmitText(wnd, len, start, msg - start);
699                         start = msg;
700                         msg+=2;
701                         while(*msg)
702                         {
703                                 if (msg[0] == '*' && msg[1] == '/')
704                                 {
705                                         msg+=2;
706                                         break;
707                                 }
708                                 msg++;
709                         }
710                 }
711                 else if (*msg == '#' || *msg == '_' || (*msg >= 'A' && *msg <= 'Z') || (*msg >= 'a' && *msg <= 'z'))
712                 {
713                         len = GUIEmitText(wnd, len, start, msg - start);
714                         start = msg;
715                         msg++;
716                         while (*msg == '_' || (*msg >= 'A' && *msg <= 'Z') || (*msg >= 'a' && *msg <= 'z' || *msg >= '0' && *msg <= '9'))
717                                 msg++;
718                 }
719                 else if (*msg == '\"')
720                 {
721                         len = GUIEmitText(wnd, len, start, msg - start);
722                         start = msg;
723                         msg++;
724                         while(*msg)
725                         {
726                                 if (*msg == '\\')
727                                         msg++;
728                                 else if (*msg == '\"')
729                                 {
730                                         msg++;
731                                         break;
732                                 }
733
734                                 msg++;
735                         }
736                 }
737 /*              else if (*msg <= ' ')
738                 {
739                         while (*msg <= ' ' && *msg)
740                                 msg++;
741                 }*/
742                 else
743                 {
744                         msg++;
745                         continue;
746                 }
747
748                 len = GUIEmitText(wnd, len, start, msg - start);
749                 start = msg;
750         }
751         len = GUIEmitText(wnd, len, start, msg - start);
752         start = msg;
753         SendMessage(wnd, WM_SETREDRAW, true, 0);
754 }
755
756 int Rehighlight(editor_t *edit)
757 {
758         int len;
759         char *file;
760
761         CHARRANGE chrg;
762         POINT scrollpos;
763
764         SendMessage(edit->editpane, EM_SETEVENTMASK, 0, 0);
765
766         SendMessage(edit->editpane, EM_GETSCROLLPOS, 0, (LPARAM)&scrollpos);
767         SendMessage(edit->editpane, EM_EXGETSEL, 0, (LPARAM) &chrg);
768
769         len = Edit_GetTextLength(edit->editpane);
770         file = malloc(len+1);
771         if (!file)
772         {
773                 MessageBox(NULL, "Save failed - not enough mem", "Error", 0);
774                 return false;
775         }
776         Edit_GetText(edit->editpane, file, len);
777         file[len] = '\0';
778
779         SetWindowText(edit->editpane,"");
780
781 //      GUIPrint(edit->editpane, file);
782         GUIFormattingPrint(edit->editpane, file);
783         free(file);
784
785 //      Edit_SetSel(edit->editpane, Edit_LineIndex(neweditor->editpane, 0), Edit_LineIndex(neweditor->editpane, 0));
786
787         InvalidateRect(edit->editpane, NULL, true);
788         InvalidateRect(edit->window, NULL, true);
789
790         SendMessage(edit->editpane, EM_SETEVENTMASK, 0, ENM_SELCHANGE|ENM_CHANGE);
791
792         SendMessage(edit->editpane, EM_SETSCROLLPOS, 0, (LPARAM)&scrollpos);
793         SendMessage(edit->editpane, EM_EXSETSEL, 0, (LPARAM) &chrg);
794
795         UpdateWindow(edit->editpane);
796         RedrawWindow(edit->window, NULL, NULL, 0);
797
798         return true;
799 }
800 #else
801 static void chunkcolour(HWND pane, int start, int end, DWORD colour)
802 {
803         CHARFORMAT cf;
804         if (colour == RGB(0,0,0))
805                 return; //don't need to
806         Edit_SetSel(pane,start,end);
807         memset(&cf, 0, sizeof(cf));
808         cf.cbSize = sizeof(cf);
809         cf.dwMask = CFM_COLOR;
810         cf.crTextColor = colour;
811         SendMessage(pane, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
812 }
813 void GUIFormattingPrint(HWND wnd, char *msg)
814 {
815 }
816 int Rehighlight(editor_t *edit)
817 {
818         char *file;
819         int c, last, len;
820         DWORD color;
821         CHARRANGE chrg;
822         POINT scrollpos;
823
824         //Dsiable redraws
825         SendMessage(edit->editpane, WM_SETREDRAW, false, 0);
826
827         //Don't notify us for a bit..
828         SendMessage(edit->editpane, EM_SETEVENTMASK, 0, 0);
829
830         //get state so we can restore scroll positions and things.
831         SendMessage(edit->editpane, EM_GETSCROLLPOS, 0, (LPARAM)&scrollpos);
832         SendMessage(edit->editpane, EM_EXGETSEL, 0, (LPARAM) &chrg);
833
834
835         len = Edit_GetTextLength(edit->editpane);
836         file = malloc(len+1);
837         if (!file)
838         {
839                 MessageBox(NULL, "Highlight failed - not enough mem", "Error", 0);
840                 return false;
841         }
842         Edit_GetText(edit->editpane, file, len);
843         file[len] = '\0';
844         SetWindowText(edit->editpane,file);     //this is so that we guarentee that the \rs or whatever that windows insists on inserting don't get in the way
845
846         color = RGB(0,0,0);
847         for (last = 0, c = 0; c < len; c++)
848         {
849                 if (file[c] == '/' && file[c+1] == '/') //do special syntax
850                 {
851                         chunkcolour(edit->editpane, last, c, color);
852                         last = c;
853
854                         while(file[c] != '\n')
855                                 c++;
856                         color = RGB(0, 127, 0);
857                 }
858                 else
859                 {
860                         chunkcolour(edit->editpane, last, c, color);
861                         last = c;
862
863                         while(file[c] >= 'a' && file[c] <= 'z' || file[c] >= 'A' && file[c] <= 'Z' || file[c] == '_')
864                                 c++;
865
866                         color = RGB(rand(), rand(), rand());
867                 }
868         }
869
870         free(file);
871
872         //reenable drawing
873         SendMessage(edit->editpane, WM_SETREDRAW, true, 0);
874 }
875 #endif
876
877 void EditorReload(editor_t *editor)
878 {
879         struct stat sbuf;
880         int flen;
881         char *file;
882
883         flen = QCC_FileSize(editor->filename);
884         if (flen >= 0)
885         {
886                 file = malloc(flen+1);
887                 QCC_ReadFile(editor->filename, file, flen);
888                 file[flen] = 0;
889         }
890
891         SendMessage(editor->editpane, EM_SETEVENTMASK, 0, 0);
892
893         /*clear it out*/
894         Edit_SetSel(editor->editpane,0,Edit_GetTextLength(editor->editpane));
895         Edit_ReplaceSel(editor->editpane,"");
896
897         if (!fl_autohighlight)
898         {
899                 GUIPrint(editor->editpane, file);
900         }
901         else
902         {
903                 GUIFormattingPrint(editor->editpane, file);
904         }
905         free(file);
906
907         editor->modified = false;
908         stat(editor->filename, &sbuf);
909         editor->filemodifiedtime = sbuf.st_mtime;
910
911         SendMessage(editor->editpane, EM_SETEVENTMASK, 0, ENM_SELCHANGE|ENM_CHANGE);
912 }
913
914 void EditFile(char *name, int line)
915 {
916         char title[1024];
917         editor_t *neweditor;
918         WNDCLASS wndclass;
919         HMENU menu, menufile, menuhelp, menunavig;
920
921         for (neweditor = editors; neweditor; neweditor = neweditor->next)
922         {
923                 if (neweditor->window && !strcmp(neweditor->filename, name))
924                 {
925                         if (line >= 0)
926                         {
927                                 Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1));
928                                 Edit_ScrollCaret(neweditor->editpane);
929                         }
930                         if (mdibox)
931                                 SendMessage(mdibox, WM_MDIACTIVATE, (WPARAM)neweditor->window, 0);
932                         SetFocus(neweditor->window);
933                         SetFocus(neweditor->editpane);
934                         return;
935                 }
936         }
937
938         if (QCC_FileSize(name) == -1)
939         {
940                 MessageBox(NULL, "File not found.", "Error", 0);
941                 return;
942         }
943
944         neweditor = malloc(sizeof(editor_t));
945         if (!neweditor)
946         {
947                 MessageBox(NULL, "Low memory", "Error", 0);
948                 return;
949         }
950
951         neweditor->next = editors;
952         editors = neweditor;
953
954         strncpy(neweditor->filename, name, sizeof(neweditor->filename)-1);
955
956         if (!mdibox)
957         {
958                 menu = CreateMenu();
959                 menufile = CreateMenu();
960                 menuhelp = CreateMenu();
961                 menunavig = CreateMenu();
962                 AppendMenu(menu, MF_POPUP, (UINT_PTR)menufile,  "&File");
963                 AppendMenu(menu, MF_POPUP, (UINT_PTR)menunavig, "&Navigation");
964                 AppendMenu(menu, MF_POPUP, (UINT_PTR)menuhelp,  "&Help");
965                 AppendMenu(menufile, 0, IDM_OPENNEW,    "Open &new file ");
966                 AppendMenu(menufile, 0, IDM_SAVE,               "&Save          ");
967         //      AppendMenu(menufile, 0, IDM_FIND,               "&Find");
968                 AppendMenu(menufile, 0, IDM_UNDO,               "&Undo          Ctrl+Z");
969                 AppendMenu(menufile, 0, IDM_REDO,               "&Redo          Ctrl+Y");
970                 AppendMenu(menunavig, 0, IDM_GOTODEF, "Go to definition");
971                 AppendMenu(menunavig, 0, IDM_OPENDOCU, "Open selected file");
972                 AppendMenu(menuhelp, 0, IDM_ABOUT, "About");
973                 AppendMenu(menu, 0, IDM_HIGHTLIGHT, "H&ighlight");
974         }
975
976
977         
978         wndclass.style      = 0;
979     wndclass.lpfnWndProc   = (WNDPROC)EditorWndProc;
980     wndclass.cbClsExtra    = 0;
981     wndclass.cbWndExtra    = 0;
982     wndclass.hInstance     = ghInstance;
983     wndclass.hIcon         = 0;
984     wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
985         wndclass.hbrBackground = (void *)COLOR_WINDOW;
986     wndclass.lpszMenuName  = 0;
987     wndclass.lpszClassName = EDIT_WINDOW_CLASS_NAME;
988         RegisterClass(&wndclass);
989
990         neweditor->window = NULL;
991         if (mdibox)
992         {
993                 MDICREATESTRUCT mcs;
994
995                 sprintf(title, "%s", name);
996
997                 mcs.szClass = EDIT_WINDOW_CLASS_NAME;
998                 mcs.szTitle = name;
999                 mcs.hOwner = ghInstance;
1000                 mcs.x = mcs.cx = CW_USEDEFAULT;
1001                 mcs.y = mcs.cy = CW_USEDEFAULT;
1002                 mcs.style = WS_OVERLAPPEDWINDOW;
1003                 mcs.lParam = 0;
1004
1005                 neweditor->window = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, 
1006                         (LONG_PTR) (LPMDICREATESTRUCT) &mcs); 
1007         }
1008         else
1009         {
1010                 sprintf(title, "%s - FTEEditor", name);
1011
1012                 neweditor->window=CreateWindow(EDIT_WINDOW_CLASS_NAME, title, WS_OVERLAPPEDWINDOW,
1013                         0, 0, 640, 480, NULL, NULL, ghInstance, NULL);
1014         }
1015
1016         if (!mdibox)
1017                 SetMenu(neweditor->window, menu);
1018
1019         if (!neweditor->window)
1020         {
1021                 MessageBox(NULL, "Failed to create editor window", "Error", 0);
1022                 return;
1023         }
1024
1025         EditorReload(neweditor);
1026
1027         if (line >= 0)
1028                 Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1));
1029         else
1030                 Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, 0), Edit_LineIndex(neweditor->editpane, 0));
1031
1032         Edit_ScrollCaret(neweditor->editpane);
1033
1034         ShowWindow(neweditor->window, SW_SHOW);
1035         SetFocus(mainwindow);
1036         SetFocus(neweditor->window);
1037         SetFocus(neweditor->editpane);
1038 }
1039
1040 int EditorSave(editor_t *edit)
1041 {
1042         struct stat sbuf;
1043         int len;
1044         char *file;
1045         len = Edit_GetTextLength(edit->editpane);
1046         file = malloc(len+1);
1047         if (!file)
1048         {
1049                 MessageBox(NULL, "Save failed - not enough mem", "Error", 0);
1050                 return false;
1051         }
1052         Edit_GetText(edit->editpane, file, len);
1053         if (!QCC_WriteFile(edit->filename, file, len))
1054         {
1055                 MessageBox(NULL, "Save failed\nCheck path and ReadOnly flags", "Failure", 0);
1056                 return false;
1057         }
1058         free(file);
1059
1060         /*now whatever is on disk should have the current time*/
1061         edit->modified = false;
1062         stat(edit->filename, &sbuf);
1063         edit->filemodifiedtime = sbuf.st_mtime;
1064
1065         return true;
1066 }
1067 void EditorsRun(void)
1068 {
1069 }
1070
1071
1072 char *GUIReadFile(const char *fname, void *buffer, int blen)
1073 {
1074         editor_t *e;
1075         for (e = editors; e; e = e->next)
1076         {
1077                 if (e->window && !strcmp(e->filename, fname))
1078                 {
1079                         int elen = Edit_GetTextLength(e->editpane);
1080                         Edit_GetText(e->editpane, buffer, blen);
1081                         return buffer;
1082                 }
1083         }
1084
1085         return QCC_ReadFile(fname, buffer, blen);
1086 }
1087
1088 int GUIFileSize(const char *fname)
1089 {
1090         editor_t *e;
1091         for (e = editors; e; e = e->next)
1092         {
1093                 if (e->window && !strcmp(e->filename, fname))
1094                 {
1095                         int len = Edit_GetTextLength(e->editpane);
1096                         return len;
1097                 }
1098         }
1099         return QCC_FileSize(fname);
1100 }
1101
1102 /*checks if the file has been modified externally*/
1103 pbool EditorModified(editor_t *e)
1104 {
1105         struct stat sbuf;
1106         stat(e->filename, &sbuf);
1107         if (e->filemodifiedtime != sbuf.st_mtime)
1108                 return true;
1109
1110         return false;
1111 }
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125 HWND optionsmenu;
1126 HWND hexen2item;
1127 HWND nokeywords_coexistitem;
1128 HWND autoprototype_item;
1129 HWND autohighlight_item;
1130 HWND extraparmsitem;
1131 static LONG CALLBACK OptionsWndProc(HWND hWnd,UINT message,
1132                                      WPARAM wParam,LPARAM lParam)
1133 {
1134         int i;
1135         switch (message)
1136         {
1137         case WM_DESTROY:
1138                 optionsmenu = NULL;
1139                 break;
1140
1141         case WM_COMMAND:
1142                 switch(wParam)
1143                 {
1144                 case IDI_O_USE:
1145                 case IDI_O_APPLY:
1146                         for (i = 0; optimisations[i].enabled; i++)
1147                         {
1148                                 if (optimisations[i].flags & FLAG_HIDDENINGUI)
1149                                         continue;
1150
1151                                 if (Button_GetCheck(optimisations[i].guiinfo))
1152                                         optimisations[i].flags |= FLAG_SETINGUI;
1153                                 else
1154                                         optimisations[i].flags &= ~FLAG_SETINGUI;
1155                         }
1156                         fl_hexen2 = Button_GetCheck(hexen2item);
1157                         for (i = 0; compiler_flag[i].enabled; i++)
1158                         {
1159                                 if (compiler_flag[i].flags & FLAG_HIDDENINGUI)
1160                                         continue;
1161                                 if (Button_GetCheck(compiler_flag[i].guiinfo))
1162                                         compiler_flag[i].flags |= FLAG_SETINGUI;
1163                                 else
1164                                         compiler_flag[i].flags &= ~FLAG_SETINGUI;
1165                         }
1166                         fl_autohighlight = Button_GetCheck(autohighlight_item);
1167                         Edit_GetText(extraparmsitem, parameters, sizeof(parameters)-1);
1168
1169                         if (wParam == IDI_O_USE)
1170                                 buttons[ID_COMPILE].washit = true;
1171                         break;
1172                 case IDI_O_CHANGE_PROGS_SRC:
1173                         {
1174                                 char *s, *s2;
1175                                 char filename[MAX_PATH];
1176                                 char oldpath[MAX_PATH+10];
1177                                 OPENFILENAME ofn;
1178                                 memset(&ofn, 0, sizeof(ofn));
1179                                 ofn.lStructSize = sizeof(ofn);
1180                                 ofn.hInstance = ghInstance;
1181                                 ofn.lpstrFile = filename;
1182                                 ofn.lpstrTitle = "Please find progs.src";
1183                                 ofn.nMaxFile = sizeof(filename)-1;
1184                                 ofn.lpstrFilter = "QuakeC source\0*.src\0All files\0*.*\0";
1185                                 memset(filename, 0, sizeof(filename));
1186                                 GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
1187                                 ofn.lpstrInitialDir = oldpath;
1188                                 if (GetOpenFileName(&ofn))
1189                                 {
1190                                         strcpy(progssrcdir, filename);
1191                                         for(s = progssrcdir; s; s = s2)
1192                                         {
1193                                                 s2 = strchr(s+1, '\\');
1194                                                 if (!s2)
1195                                                         break;
1196                                                 s = s2;
1197                                         }
1198                                         if (s)
1199                                         {
1200                                                 *s = '\0';
1201                                                 strcpy(progssrcname, s+1);
1202                                         }
1203                                         else
1204                                                 strcpy(progssrcname, filename);
1205
1206                                         SetCurrentDirectory(progssrcdir);
1207                                         *progssrcdir = '\0';
1208                                 }
1209                                 resetprogssrc = true;
1210                         }
1211                         break;
1212                 case IDI_O_LEVEL0:
1213                 case IDI_O_LEVEL1:
1214                 case IDI_O_LEVEL2:
1215                 case IDI_O_LEVEL3:
1216                         for (i = 0; optimisations[i].enabled; i++)
1217                         {
1218                                 if (optimisations[i].flags & FLAG_HIDDENINGUI)
1219                                         continue;
1220
1221                                 if (optimisations[i].optimisationlevel<=(int)wParam-IDI_O_LEVEL0)
1222                                         Button_SetCheck(optimisations[i].guiinfo, 1);
1223                                 else
1224                                         Button_SetCheck(optimisations[i].guiinfo, 0);
1225                         }
1226                         break;
1227                 case IDI_O_DEBUG:
1228                         for (i = 0; optimisations[i].enabled; i++)
1229                         {
1230                                 if (optimisations[i].flags & FLAG_HIDDENINGUI)
1231                                         continue;
1232
1233                                 if (optimisations[i].flags&FLAG_KILLSDEBUGGERS)
1234                                         Button_SetCheck(optimisations[i].guiinfo, 0);
1235                         }
1236                         break;
1237                 case IDI_O_DEFAULT:
1238                         for (i = 0; optimisations[i].enabled; i++)
1239                         {
1240                                 if (optimisations[i].flags & FLAG_HIDDENINGUI)
1241                                         continue;
1242
1243                                 if (optimisations[i].flags & FLAG_ASDEFAULT)
1244                                         Button_SetCheck(optimisations[i].guiinfo, 1);
1245                                 else
1246                                         Button_SetCheck(optimisations[i].guiinfo, 0);
1247                         }
1248                         break;
1249                 }
1250                 break;
1251         case WM_HELP:
1252                 {
1253                         HELPINFO *hi;
1254                         hi = (HELPINFO *)lParam;
1255                         switch(hi->iCtrlId) 
1256                         {
1257                         case IDI_O_DEFAULT:
1258                                 MessageBox(hWnd, "Sets the default optimisations", "Help", MB_OK|MB_ICONINFORMATION);
1259                                 break;
1260                         case IDI_O_DEBUG:
1261                                 MessageBox(hWnd, "Clears all optimisations which can make your progs harder to debug", "Help", MB_OK|MB_ICONINFORMATION);
1262                                 break;
1263                         case IDI_O_LEVEL0:
1264                         case IDI_O_LEVEL1:
1265                         case IDI_O_LEVEL2:
1266                         case IDI_O_LEVEL3:
1267                                 MessageBox(hWnd, "Sets a specific optimisation level", "Help", MB_OK|MB_ICONINFORMATION);
1268                                 break;
1269                         case IDI_O_CHANGE_PROGS_SRC:
1270                                 MessageBox(hWnd, "Use this button to change your root source file.\nNote that fteqcc compiles sourcefiles from editors first, rather than saving. This means that changes are saved ONLY when you save them, but means that switching project mid-compile can result in problems.", "Help", MB_OK|MB_ICONINFORMATION);
1271                                 break;
1272                         case IDI_O_ADDITIONALPARAMETERS:
1273                                 MessageBox(hWnd, "Type in additional commandline parameters here. Use -Dname to define a named precompiler constant before compiling.", "Help", MB_OK|MB_ICONINFORMATION);
1274                                 break;
1275                         case IDI_O_APPLY:
1276                                 MessageBox(hWnd, "Apply changes shown, but do not recompile yet.", "Help", MB_OK|MB_ICONINFORMATION);
1277                                 break;
1278                         case IDI_O_USE:
1279                                 MessageBox(hWnd, "Apply changes shown here and recompile.", "Help", MB_OK|MB_ICONINFORMATION);
1280                                 break;
1281                         case IDI_O_OPTIMISATION:
1282                                 for (i = 0; optimisations[i].enabled; i++)
1283                                 {
1284                                         if (optimisations[i].guiinfo == hi->hItemHandle)
1285                                         {
1286                                                 MessageBox(hWnd, optimisations[i].description, "Help", MB_OK|MB_ICONINFORMATION);
1287                                                 break;
1288                                         }
1289                                 }
1290                                 break;
1291                         case IDI_O_COMPILER_FLAG:
1292                                 for (i = 0; compiler_flag[i].enabled; i++)
1293                                 {
1294                                         if (compiler_flag[i].guiinfo == hi->hItemHandle)
1295                                         {
1296                                                 MessageBox(hWnd, compiler_flag[i].description, "Help", MB_OK|MB_ICONINFORMATION);
1297                                                 break;
1298                                         }
1299                                 }
1300                                 break;
1301                         case IDI_O_TARGET:
1302                                 MessageBox(hWnd, "Click here to compile a hexen2 compatible progs. Note that this uses the -Thexen2. There are other targets available.", "Help", MB_OK|MB_ICONINFORMATION);
1303                                 break;
1304                         case IDI_O_SYNTAX_HIGHLIGHTING:
1305                                 MessageBox(hWnd, "Should syntax be highlighted automatically when a file is opened?", "Help", MB_OK|MB_ICONINFORMATION);
1306                                 break;
1307                         }
1308                 }
1309                 break;
1310         default:
1311                 return DefWindowProc(hWnd,message,wParam,lParam);
1312         }
1313         return 0;
1314 }
1315 void OptionsDialog(void)
1316 {
1317         HWND subsection;
1318         RECT r;
1319         WNDCLASS wndclass;
1320         HWND wnd;
1321         int i;
1322         int flagcolums=1;
1323
1324         int x;
1325         int y;
1326         int my;
1327         int height;
1328         int num;
1329         int cflagsshown;
1330
1331         if (optionsmenu)
1332         {
1333                 BringWindowToTop(optionsmenu);
1334                 return;
1335         }
1336
1337
1338         memset(&wndclass, 0, sizeof(wndclass));
1339         wndclass.style      = 0;
1340     wndclass.lpfnWndProc   = (WNDPROC)OptionsWndProc;
1341     wndclass.cbClsExtra    = 0;
1342     wndclass.cbWndExtra    = 0;
1343     wndclass.hInstance     = ghInstance;
1344     wndclass.hIcon         = 0;
1345     wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
1346         wndclass.hbrBackground = (void *)COLOR_WINDOW;
1347     wndclass.lpszMenuName  = 0;
1348     wndclass.lpszClassName = OPTIONS_WINDOW_CLASS_NAME;
1349         RegisterClass(&wndclass);
1350
1351         height = 0;
1352         for (i = 0; optimisations[i].enabled; i++)
1353         {
1354                 if (optimisations[i].flags & FLAG_HIDDENINGUI)
1355                         continue;
1356
1357                 height++;
1358         }
1359
1360         cflagsshown = 2;
1361         for (i = 0; compiler_flag[i].enabled; i++)
1362         {
1363                 if (compiler_flag[i].flags & FLAG_HIDDENINGUI)
1364                         continue;
1365
1366                 cflagsshown++;
1367         }
1368
1369         height = (height-1)/2;
1370
1371         while (cflagsshown > ((480-(88+40))/16)*(flagcolums))
1372                 flagcolums++;
1373
1374         if (height < (cflagsshown+flagcolums-1)/flagcolums)
1375                 height = (cflagsshown+flagcolums-1)/flagcolums;
1376
1377         r.right = 408 + flagcolums*168;
1378         if (r.right < 640)
1379                 r.right = 640;
1380
1381         height *= 16;
1382
1383         height += 88+40;
1384
1385         r.left = GetSystemMetrics(SM_CXSCREEN)/2-320;
1386         r.top = GetSystemMetrics(SM_CYSCREEN)/2-240;
1387         r.bottom = r.top + height;
1388         r.right  += r.left;
1389
1390
1391
1392         AdjustWindowRectEx (&r, WS_CAPTION|WS_SYSMENU, FALSE, 0);
1393
1394         optionsmenu=CreateWindowEx(WS_EX_CONTEXTHELP, OPTIONS_WINDOW_CLASS_NAME, "Options - FTE QuakeC compiler", WS_CAPTION|WS_SYSMENU,
1395                 r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, ghInstance, NULL);
1396
1397         subsection = CreateWindow("BUTTON", "Optimisations", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
1398                 0, 0, 400, height-48, optionsmenu, NULL, ghInstance, NULL);
1399
1400         num = 0;
1401         for (i = 0; optimisations[i].enabled; i++)
1402         {
1403                 if (optimisations[i].flags & FLAG_HIDDENINGUI)
1404                 {
1405                         optimisations[i].guiinfo = NULL;
1406                         continue;
1407                 }
1408
1409                 optimisations[i].guiinfo = wnd = CreateWindow("BUTTON",optimisations[i].fullname,
1410                            WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
1411                            8+200*(num&1),16+16*(num/2),200-16,16,
1412                            subsection,
1413                            (HMENU)IDI_O_OPTIMISATION,
1414                            ghInstance,
1415                            NULL);
1416
1417                 if (optimisations[i].flags&FLAG_SETINGUI)
1418                         Button_SetCheck(wnd, 1);
1419                 else
1420                         Button_SetCheck(wnd, 0);
1421
1422                 num++;
1423         }
1424
1425         CreateWindow("BUTTON","O0",
1426                    WS_CHILD | WS_VISIBLE,
1427                    8,height-88,64,32,
1428                    optionsmenu,
1429                    (HMENU)IDI_O_LEVEL0,
1430                    ghInstance,
1431                    NULL);
1432         CreateWindow("BUTTON","O1",
1433                    WS_CHILD | WS_VISIBLE,
1434                    8+64,height-88,64,32,
1435                    optionsmenu,
1436                    (HMENU)IDI_O_LEVEL1,
1437                    ghInstance,
1438                    NULL);
1439         CreateWindow("BUTTON","O2",
1440                    WS_CHILD | WS_VISIBLE,
1441                    8+64*2,height-88,64,32,
1442                    optionsmenu,
1443                    (HMENU)IDI_O_LEVEL2,
1444                    ghInstance,
1445                    NULL);
1446         CreateWindow("BUTTON","O3",
1447                    WS_CHILD | WS_VISIBLE,
1448                    8+64*3,height-88,64,32,
1449                    optionsmenu,
1450                    (HMENU)IDI_O_LEVEL3,
1451                    ghInstance,
1452                    NULL);
1453         CreateWindow("BUTTON","Debug",
1454                    WS_CHILD | WS_VISIBLE,
1455                    8+64*4,height-88,64,32,
1456                    optionsmenu,
1457                    (HMENU)IDI_O_DEBUG,
1458                    ghInstance,
1459                    NULL);
1460         CreateWindow("BUTTON","Default",
1461                    WS_CHILD | WS_VISIBLE,
1462                    8+64*5,height-88,64,32,
1463                    optionsmenu,
1464                    (HMENU)IDI_O_DEFAULT,
1465                    ghInstance,
1466                    NULL);
1467         CreateWindow("BUTTON","Apply",
1468                    WS_CHILD | WS_VISIBLE,
1469                    8,height-40,64,32,
1470                    optionsmenu,
1471                    (HMENU)IDI_O_APPLY,
1472                    ghInstance,
1473                    NULL);
1474         CreateWindow("BUTTON","Use",
1475                    WS_CHILD | WS_VISIBLE,
1476                    8+64,height-40,64,32,
1477                    optionsmenu,
1478                    (HMENU)IDI_O_USE,
1479                    ghInstance,
1480                    NULL);
1481         CreateWindow("BUTTON","progs.src",
1482                    WS_CHILD | WS_VISIBLE,
1483                    8+64*2,height-40,64,32,
1484                    optionsmenu,
1485                    (HMENU)IDI_O_CHANGE_PROGS_SRC,
1486                    ghInstance,
1487                    NULL);
1488
1489
1490
1491                 y=4;
1492         hexen2item = wnd = CreateWindow("BUTTON","HexenC",
1493                    WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
1494                    408,y,200-16,16,
1495                    optionsmenu,
1496                    (HMENU)IDI_O_TARGET,
1497                    ghInstance,
1498                    NULL);
1499         y+=16;
1500         if (fl_hexen2)
1501                 Button_SetCheck(wnd, 1);
1502         else
1503                 Button_SetCheck(wnd, 0);
1504
1505         autohighlight_item = wnd = CreateWindow("BUTTON","Syntax Highlighting",
1506                    WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
1507                    408,y,200-16,16,
1508                    optionsmenu,
1509                    (HMENU)IDI_O_SYNTAX_HIGHLIGHTING,
1510                    ghInstance,
1511                    NULL);
1512         y+=16;
1513         if (fl_autohighlight)
1514                 Button_SetCheck(wnd, 1);
1515         else
1516                 Button_SetCheck(wnd, 0);
1517
1518         x = 408;
1519         my = y;
1520         for (i = 0; compiler_flag[i].enabled; i++)
1521         {
1522                 if (compiler_flag[i].flags & FLAG_HIDDENINGUI)
1523                 {
1524                         compiler_flag[i].guiinfo = NULL;
1525                         continue;
1526                 }
1527
1528                 if (y > height-(88+40))
1529                 {
1530                         y = 4;
1531                         x += 168;
1532                 }
1533
1534                 compiler_flag[i].guiinfo = wnd = CreateWindow("BUTTON",compiler_flag[i].fullname,
1535                            WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
1536                            x,y,168,16,
1537                            optionsmenu,
1538                            (HMENU)IDI_O_COMPILER_FLAG,
1539                            ghInstance,
1540                            NULL);
1541                 y+=16;
1542
1543                 if (my < y)
1544                         my = y;
1545
1546                 if (compiler_flag[i].flags & FLAG_SETINGUI)
1547                         Button_SetCheck(wnd, 1);
1548                 else
1549                         Button_SetCheck(wnd, 0);
1550         }
1551
1552         CreateWindow("STATIC","Extra Parameters:",
1553                    WS_CHILD | WS_VISIBLE,
1554                    408,my,200-16,16,
1555                    optionsmenu,
1556                    (HMENU)0,
1557                    ghInstance,
1558                    NULL);
1559         my+=16;
1560         extraparmsitem = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT",parameters,
1561                    WS_CHILD | WS_VISIBLE|ES_LEFT | ES_WANTRETURN |
1562                 ES_MULTILINE | ES_AUTOVSCROLL,
1563                    408,my,r.right-r.left - 408 - 8,height-my-4,
1564                    optionsmenu,
1565                    (HMENU)IDI_O_ADDITIONALPARAMETERS,
1566                    ghInstance,
1567                    NULL);
1568
1569         ShowWindow(optionsmenu, SW_SHOWDEFAULT);
1570 }
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582 #undef printf
1583
1584
1585
1586 static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
1587                                      WPARAM wParam,LPARAM lParam)
1588 {
1589         int width;
1590         int i;
1591         RECT rect;
1592         HDC hdc;
1593         PAINTSTRUCT ps;
1594         switch (message)
1595         {
1596         case WM_CREATE:
1597                 {
1598                         CLIENTCREATESTRUCT ccs;
1599
1600                         HMENU rootmenu, windowmenu, m;
1601                         rootmenu = CreateMenu();
1602                         
1603                                 AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()),    "&File");
1604                                         AppendMenu(m, 0, IDM_OPENNEW,   "Open &new file ");
1605                                         AppendMenu(m, 0, IDM_SAVE,              "&Save          ");
1606                                 //      AppendMenu(m, 0, IDM_FIND,              "&Find");
1607                                         AppendMenu(m, 0, IDM_UNDO,              "&Undo          Ctrl+Z");
1608                                         AppendMenu(m, 0, IDM_REDO,              "&Redo          Ctrl+Y");
1609                                 AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()),    "&Navigation");
1610                                         AppendMenu(m, 0, IDM_GOTODEF, "Go to definition");
1611                                         AppendMenu(m, 0, IDM_OPENDOCU, "Open selected file");
1612                                 AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = windowmenu = CreateMenu()),       "&Window");
1613                                         AppendMenu(m, 0, IDM_CASCADE, "&Cascade");
1614                                         AppendMenu(m, 0, IDM_TILE_HORIZ, "Tile &Horizontally");
1615                                         AppendMenu(m, 0, IDM_TILE_VERT, "Tile &Vertically");
1616                                 AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()),    "&Help");
1617                                         AppendMenu(m, 0, IDM_ABOUT, "About");
1618
1619                         SetMenu(hWnd, rootmenu);
1620
1621                         // Retrieve the handle to the window menu and assign the
1622                         // first child window identifier.
1623
1624                         memset(&ccs, 0, sizeof(ccs));
1625                         ccs.hWindowMenu = windowmenu;
1626                         ccs.idFirstChild = IDM_FIRSTCHILD;
1627
1628                         // Create the MDI client window.
1629
1630                         mdibox = CreateWindow( "MDICLIENT", (LPCTSTR) NULL,
1631                                         WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
1632                                         0, 0, 320, 200, hWnd, (HMENU) 0xCAC, ghInstance, (LPSTR) &ccs);
1633                         ShowWindow(mdibox, SW_SHOW);
1634
1635                         projecttree = CreateWindow(WC_TREEVIEW, (LPCTSTR) NULL,
1636                                         WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL
1637                                         |       TVS_HASBUTTONS |TVS_LINESATROOT|TVS_HASLINES,
1638                         0, 0, 320, 200, hWnd, (HMENU) 0xCAC, ghInstance, (LPSTR) &ccs);
1639                         ShowWindow(projecttree, SW_SHOW);
1640
1641                         if (projecttree)
1642                         {
1643                                 gotodefbox = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", (LPCTSTR) NULL,
1644                                                 WS_CHILD | WS_CLIPCHILDREN,
1645                                                 0, 0, 320, 200, hWnd, (HMENU) 0xCAC, ghInstance, (LPSTR) NULL);
1646                                 ShowWindow(gotodefbox, SW_SHOW);
1647
1648                                 gotodefaccept = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "GO",
1649                                                 WS_CHILD | WS_CLIPCHILDREN | BS_DEFPUSHBUTTON,
1650                                                 0, 0, 320, 200, hWnd, (HMENU) 0x4404, ghInstance, (LPSTR) NULL);
1651                                 ShowWindow(gotodefaccept, SW_SHOW);
1652                         }
1653                 }
1654                 break;
1655
1656         case WM_DESTROY:
1657                 mainwindow = NULL;
1658                 break;
1659
1660         case WM_SIZE:
1661                 GetClientRect(mainwindow, &rect);
1662                 if (projecttree)
1663                 {
1664                         SetWindowPos(projecttree, NULL, 0, 0, 192, rect.bottom-rect.top - 34 - 24, 0);
1665
1666                         SetWindowPos(gotodefbox, NULL, 0, rect.bottom-rect.top - 33 - 24, 160, 24, 0);
1667                         SetWindowPos(gotodefaccept, NULL, 160, rect.bottom-rect.top - 33 - 24, 32, 24, 0);
1668                         SetWindowPos(mdibox?mdibox:outputbox, NULL, 192, 0, rect.right-rect.left-192, rect.bottom-rect.top - 32, 0);
1669                 }
1670                 else
1671                         SetWindowPos(mdibox?mdibox:outputbox, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top - 32, 0);
1672                 width = (rect.right-rect.left);
1673                 width/=NUMBUTTONS;
1674                 for (i = 0; i < NUMBUTTONS; i++)
1675                 {
1676                         SetWindowPos(buttons[i].hwnd, NULL, width*i, rect.bottom-rect.top - 32, width, 32, 0);
1677                 }
1678                 break;
1679         case WM_PAINT:
1680                 hdc=BeginPaint(hWnd,(LPPAINTSTRUCT)&ps);
1681
1682                 EndPaint(hWnd,(LPPAINTSTRUCT)&ps);
1683                 return TRUE;
1684                 break;
1685         case WM_COMMAND:
1686                 if (wParam == 0x4404)
1687                 {
1688                         GetWindowText(gotodefbox, finddef, sizeof(finddef)-1);
1689                         return true;
1690                 }
1691                 if (LOWORD(wParam)>0 && LOWORD(wParam) <= NUMBUTTONS)
1692                 {
1693                         if (LOWORD(wParam))
1694                                 buttons[LOWORD(wParam)-1].washit = 1;
1695                         break;
1696                 }
1697                 if (LOWORD(wParam) < IDM_FIRSTCHILD)
1698                 {
1699                         HWND ew;
1700                         editor_t *editor;
1701         
1702                         ew = (HWND)SendMessage(mdibox, WM_MDIGETACTIVE, 0, 0);
1703
1704                         for (editor = editors; editor; editor = editor->next)
1705                         {
1706                                 if (editor->window == ew)
1707                                         break;
1708                         }
1709                         if (editor)
1710                                 EditorMenu(editor, wParam);
1711                         else
1712                                 GenericMenu(wParam);
1713                         break;
1714                 }
1715                 break;
1716         case WM_NOTIFY:
1717                 if (lParam)
1718                 {
1719                         NMHDR *nm;
1720                         HANDLE item;
1721                         TVITEM i;
1722                         char filename[256];
1723                         char itemtext[256];
1724                         int oldlen;
1725                         int newlen;
1726                         nm = (NMHDR*)lParam;
1727                         if (nm->hwndFrom == projecttree)
1728                         {
1729                                 switch(nm->code)
1730                                 {
1731                                 case NM_DBLCLK:
1732                                         item = TreeView_GetSelection(projecttree);
1733                                         i.hItem = item;
1734                                         i.mask = TVIF_TEXT;
1735                                         i.pszText = itemtext;
1736                                         i.cchTextMax = sizeof(itemtext)-1;
1737                                         if (!TreeView_GetItem(projecttree, &i))
1738                                                 return 0;
1739                                         strcpy(filename, i.pszText);
1740                                         while(item)
1741                                         {
1742                                                 item = TreeView_GetParent(projecttree, item);
1743                                                 i.hItem = item;
1744                                                 if (!TreeView_GetItem(projecttree, &i))
1745                                                         break;
1746                                                 if (!TreeView_GetParent(projecttree, item))
1747                                                         break;
1748
1749                                                 oldlen = strlen(filename);
1750                                                 newlen = strlen(i.pszText);
1751                                                 memmove(filename+newlen+1, filename, oldlen+1);
1752                                                 filename[newlen] = '/';
1753                                                 strncpy(filename, i.pszText, newlen);
1754                                         }
1755                                         EditFile(filename, -1);
1756                                         break;
1757                                 }
1758                         }
1759                 }
1760         default:
1761                 if (mdibox)
1762                         return DefFrameProc(hWnd,mdibox,message,wParam,lParam);
1763                 else
1764                         return DefWindowProc(hWnd,message,wParam,lParam);
1765         }
1766         return 0;
1767 }
1768
1769 static LONG CALLBACK OutputWindowProc(HWND hWnd,UINT message,
1770                                      WPARAM wParam,LPARAM lParam)
1771 {
1772         RECT rect;
1773         switch (message)
1774         {
1775         case WM_DESTROY:
1776                 outputwindow = NULL;
1777                 outputbox = NULL;
1778                 break;
1779         case WM_CREATE:
1780                 outputbox = CreateAnEditControl(hWnd);
1781         case WM_SIZE:
1782                 GetClientRect(hWnd, &rect);
1783                 SetWindowPos(outputbox, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0);
1784
1785         default:
1786                 return DefMDIChildProc(hWnd,message,wParam,lParam);
1787         }
1788         return 0;
1789 }
1790
1791 void GUIPrint(HWND wnd, char *msg)
1792 {
1793         MSG        wmsg;
1794         int len;
1795         static int writing;
1796
1797         if (writing)
1798                 return;
1799         if (!mainwindow)
1800         {
1801                 printf("%s", msg);
1802                 return;
1803         }
1804         writing=true;
1805         len=Edit_GetTextLength(wnd);
1806 /*      if ((unsigned)len>(32767-strlen(msg)))
1807                 Edit_SetSel(wnd,0,len);
1808         else*/
1809                 Edit_SetSel(wnd,len,len);
1810         Edit_ReplaceSel(wnd,msg);
1811
1812         while (PeekMessage (&wmsg, NULL, 0, 0, PM_NOREMOVE))
1813         {
1814                 if (!GetMessage (&wmsg, NULL, 0, 0))
1815                         break;
1816                 TranslateMessage (&wmsg);
1817                 DispatchMessage (&wmsg);
1818         }
1819         writing=false;
1820 }
1821 int GUIEmitOutputText(HWND wnd, int start, char *text, int len, DWORD colour)
1822 {
1823         int c, cr;
1824         CHARFORMAT cf;
1825
1826         if (!len)
1827                 return start;
1828
1829         c = text[len];
1830         text[len] = '\0';
1831         Edit_SetSel(wnd,start,start);
1832         Edit_ReplaceSel(wnd,text);
1833
1834         text[len] = c;
1835
1836         cr = 0;
1837         for (c = 0; c < len; c++)
1838                 if (text[c] == '\r')
1839                         cr++;
1840         if (cr)
1841                 len-=cr;
1842
1843         Edit_SetSel(wnd,start,start+len);
1844         memset(&cf, 0, sizeof(cf));
1845         cf.cbSize = sizeof(cf);
1846         cf.dwMask = CFM_COLOR;
1847         cf.crTextColor = colour;
1848         SendMessage(wnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
1849         Edit_SetSel(wnd,start+len,start+len);
1850
1851         return start + len;
1852 }
1853 int outlen;
1854 int GUIprintf(const char *msg, ...)
1855 {
1856         va_list         argptr;
1857         char            buf[1024];
1858         char rn[3] = "\n";
1859         char *st, *s;
1860         int args;
1861         MSG        wmsg;
1862
1863         DWORD col;
1864
1865         va_start (argptr,msg);
1866         args = QC_vsnprintf (buf,sizeof(buf)-1, msg,argptr);
1867         va_end (argptr);
1868
1869         printf("%s", buf);
1870         if (logfile)
1871                 fprintf(logfile, "%s", buf);
1872
1873         if (!*buf)
1874         {
1875                 SetWindowText(outputbox,"");
1876                 outlen = 0;
1877                 return 0;
1878         }
1879
1880         if (strstr(buf, "warning: "))
1881                 col = RGB(128, 128, 0);
1882         else if (strstr(buf, "error: "))
1883                 col = RGB(255, 0, 0);
1884         else
1885                 col = RGB(0, 0, 0);
1886
1887         s = st = buf;
1888         while(*s)
1889         {
1890                 if (*s == '\n')
1891                 {
1892                         *s = '\0';
1893                         if (*st)
1894                                 outlen = GUIEmitOutputText(outputbox, outlen, st, strlen(st), col);
1895                         outlen = GUIEmitOutputText(outputbox, outlen, rn, 1, col);
1896                         st = s+1;
1897                 }
1898
1899                 s++;
1900         }
1901         if (*st)
1902                 outlen = GUIEmitOutputText(outputbox, outlen, st, strlen(st), col);
1903
1904         while (PeekMessage (&wmsg, NULL, 0, 0, PM_NOREMOVE))
1905         {
1906                 if (!GetMessage (&wmsg, NULL, 0, 0))
1907                         break;
1908                 TranslateMessage (&wmsg);
1909                 DispatchMessage (&wmsg);
1910         }
1911 /*
1912         s = st = buf;
1913         while(*s)
1914         {
1915                 if (*s == '\n')
1916                 {
1917                         *s = '\0';
1918                         if (*st)
1919                                 GUIPrint(outputbox, st);
1920                         GUIPrint(outputbox, "\r\n");
1921                         st = s+1;
1922                 }
1923
1924                 s++;
1925         }
1926         if (*st)
1927                 GUIPrint(outputbox, st);
1928 */
1929         return args;
1930 }
1931
1932 #undef Sys_Error
1933
1934 void Sys_Error(const char *text, ...);
1935 void RunCompiler(char *args)
1936 {
1937         char *argv[128];
1938         int argc;
1939         progexterns_t ext;
1940         progfuncs_t funcs;
1941
1942         editor_t *editor;
1943         for (editor = editors; editor; editor = editor->next)
1944         {
1945                 if (editor->modified)
1946                 {
1947                         if (EditorModified(editor))
1948                         {
1949                                 char msg[1024];
1950                                 sprintf(msg, "%s is modified in both memory and on disk. Overwrite external modification? (saying no will reload from disk)", editor->filename);
1951                                 switch(MessageBox(NULL, msg, "Modification conflict", MB_YESNOCANCEL))
1952                                 {
1953                                 case IDYES:
1954                                         EditorSave(editor);
1955                                         break;
1956                                 case IDNO:
1957                                         EditorReload(editor);
1958                                         break;
1959                                 case IDCANCEL:
1960                                         break; /*compiling will use whatever is in memory*/
1961                                 }
1962                         }
1963                         else
1964                         {
1965                                 /*not modified on disk, but modified in memory? try and save it, cos we might as well*/
1966                                 EditorSave(editor);
1967                         }
1968                 }
1969                 else
1970                 {
1971                         /*modified on disk but not in memory? just reload it off disk*/
1972                         if (EditorModified(editor))
1973                                 EditorReload(editor);
1974                 }
1975         }
1976
1977         memset(&funcs, 0, sizeof(funcs));
1978         funcs.parms = &ext;
1979         memset(&ext, 0, sizeof(ext));
1980         funcs.parms->ReadFile = GUIReadFile;
1981         funcs.parms->FileSize = GUIFileSize;
1982         funcs.parms->WriteFile = QCC_WriteFile;
1983         funcs.parms->printf = GUIprintf;
1984         funcs.parms->Sys_Error = Sys_Error;
1985         GUIprintf("");
1986         
1987         if (logfile)
1988                 fclose(logfile);
1989         if (fl_log)
1990                 logfile = fopen("fteqcc.log", "wb");
1991         else
1992                 logfile = NULL;
1993
1994         argc = GUI_BuildParms(args, argv);
1995
1996         CompileParams(&funcs, true, argc, argv);
1997
1998         if (logfile)
1999                 fclose(logfile);
2000 }
2001
2002
2003 void CreateOutputWindow(void)
2004 {
2005         WNDCLASS wndclass;
2006         MDICREATESTRUCT mcs;
2007
2008         if (!mdibox)    //should already be created
2009                 return;
2010
2011         if (!outputwindow)
2012         {
2013                 wndclass.style      = 0;
2014                 wndclass.lpfnWndProc   = (WNDPROC)OutputWindowProc;
2015                 wndclass.cbClsExtra    = 0;
2016                 wndclass.cbWndExtra    = 0;
2017                 wndclass.hInstance     = ghInstance;
2018                 wndclass.hIcon         = 0;
2019                 wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
2020                 wndclass.hbrBackground = (void *)COLOR_WINDOW;
2021                 wndclass.lpszMenuName  = 0;
2022                 wndclass.lpszClassName = MAIN_WINDOW_CLASS_NAME;
2023                 RegisterClass(&wndclass);
2024
2025
2026
2027                 mcs.szClass = MAIN_WINDOW_CLASS_NAME;
2028                 mcs.szTitle = "Compiler output";
2029                 mcs.hOwner = ghInstance;
2030                 mcs.x = mcs.cx = CW_USEDEFAULT;
2031                 mcs.y = mcs.cy = CW_USEDEFAULT;
2032                 mcs.style = WS_OVERLAPPEDWINDOW;
2033                 mcs.lParam = 0;
2034
2035                 outputwindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, 
2036                 (LONG_PTR) (LPMDICREATESTRUCT) &mcs); 
2037
2038                 ShowWindow(outputwindow, SW_SHOW);
2039         }
2040
2041         //bring it to the front.
2042         SendMessage(mdibox, WM_MDIACTIVATE, (WPARAM)outputwindow, 0);
2043 }
2044
2045 //progssrcname should already have been set.
2046 void SetProgsSrc(void)
2047 {
2048         FILE *f;
2049
2050         HANDLE rootitem, pi;
2051         TVINSERTSTRUCT item;
2052         TV_ITEM parent;
2053         char parentstring[256];
2054         memset(&item, 0, sizeof(item));
2055         memset(&parent, 0, sizeof(parent));
2056
2057         if (projecttree)
2058         {
2059                 int size;
2060                 char *buffer;
2061                 char *slash;
2062
2063                 f = fopen (progssrcname, "rb");
2064                 if (!f)
2065                         return;
2066                 fseek(f, 0, SEEK_END);
2067                 size = ftell(f);
2068                 fseek(f, 0, SEEK_SET);
2069                 buffer = malloc(size+1);
2070                 if (!buffer)
2071                 {
2072                         fclose(f);
2073                         return;
2074                 }
2075                 buffer[size] = '\0';
2076                 fread(buffer, 1, size, f);
2077                 fclose(f);
2078
2079                 pr_file_p = QCC_COM_Parse(buffer);
2080                 if (*qcc_token == '#')
2081                 {
2082                         free(buffer);   //aaaahhh! newstyle!
2083                         return;
2084                 }
2085
2086                 pr_file_p = QCC_COM_Parse(pr_file_p);   //we dont care about the produced progs.dat
2087
2088
2089                 item.hParent = TVI_ROOT;
2090                 item.hInsertAfter = TVI_SORT;
2091                 item.item.pszText = progssrcname;
2092                 item.item.mask = TVIF_TEXT;
2093                 rootitem = (HANDLE)SendMessage(projecttree,TVM_INSERTITEM,0,(LPARAM)&item);
2094                 while(pr_file_p)
2095                 {
2096                         pi = item.hParent = rootitem;
2097                         item.item.pszText = qcc_token;
2098                         while(slash = strchr(item.item.pszText, '/'))
2099                         {
2100                                 *slash = '\0';
2101                                 item.hParent = TreeView_GetChild(projecttree, item.hParent);
2102                                 do
2103                                 {
2104                                         parent.hItem = item.hParent;
2105                                         parent.mask = TVIF_TEXT;
2106                                         parent.pszText = parentstring;
2107                                         parent.cchTextMax = sizeof(parentstring)-1;
2108                                         if (TreeView_GetItem(projecttree, &parent))
2109                                         {
2110                                                 if (!stricmp(parent.pszText, item.item.pszText))
2111                                                         break;
2112                                         }
2113                                 } while(item.hParent=TreeView_GetNextSibling(projecttree, item.hParent));
2114                                 if (!item.hParent)
2115                                 {       //add a directory.
2116                                         item.hParent = pi;
2117                                         pi = (HANDLE)SendMessage(projecttree,TVM_INSERTITEM,0,(LPARAM)&item);
2118                                         item.hParent = pi;
2119                                 }
2120                                 else pi = item.hParent;
2121
2122                                 item.item.pszText = slash+1;
2123                         }
2124                         SendMessage(projecttree,TVM_INSERTITEM,0,(LPARAM)&item);
2125                         pr_file_p = QCC_COM_Parse(pr_file_p);
2126                 }
2127
2128                 free(buffer);
2129         }
2130 }
2131
2132 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
2133 {
2134         unsigned int i;
2135         WNDCLASS wndclass;
2136         ghInstance= hInstance;
2137
2138         GUI_SetDefaultOpts();
2139
2140         if(strstr(lpCmdLine, "-stdout"))
2141         {
2142                 GUI_ParseCommandLine(lpCmdLine);
2143                 RunCompiler(lpCmdLine);
2144                 return 0;
2145         }
2146
2147         if (!*lpCmdLine)
2148         {
2149                 int len;
2150                 FILE *f;
2151                 char *s;
2152
2153                 f = fopen("fteqcc.cfg", "rb");
2154                 if (f)
2155                 {
2156                         fseek(f, 0, SEEK_END);
2157                         len = ftell(f);
2158                         fseek(f, 0, SEEK_SET);
2159                         lpCmdLine = malloc(len+1);
2160                         fread(lpCmdLine, 1, len, f);
2161                         lpCmdLine[len] = '\0';
2162                         fclose(f);
2163
2164                         while(s = strchr(lpCmdLine, '\r'))
2165                                 *s = ' ';
2166                         while(s = strchr(lpCmdLine, '\n'))
2167                                 *s = ' ';
2168                 }
2169         }
2170
2171         GUI_ParseCommandLine(lpCmdLine);
2172
2173         GUI_RevealOptions();
2174
2175         if (/*!fl_acc &&*/ !*progssrcname)
2176         {
2177                 strcpy(progssrcname, "preprogs.src");
2178                 if (QCC_FileSize(progssrcname)==-1)
2179                         strcpy(progssrcname, "progs.src");
2180                 if (QCC_FileSize(progssrcname)==-1)
2181                 {
2182                         char *s, *s2;
2183                         char filename[MAX_PATH];
2184                         char oldpath[MAX_PATH+10];
2185                         OPENFILENAME ofn;
2186                         memset(&ofn, 0, sizeof(ofn));
2187                         ofn.lStructSize = sizeof(ofn);
2188                         ofn.hInstance = ghInstance;
2189                         ofn.lpstrFile = filename;
2190                         ofn.lpstrTitle = "Please find progs.src";
2191                         ofn.nMaxFile = sizeof(filename)-1;
2192                         ofn.lpstrFilter = "QuakeC source\0*.src\0All files\0*.*\0";
2193                         memset(filename, 0, sizeof(filename));
2194                         GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
2195                         ofn.lpstrInitialDir = oldpath;
2196                         if (GetOpenFileName(&ofn))
2197                         {
2198                                 strcpy(progssrcdir, filename);
2199                                 for(s = progssrcdir; s; s = s2)
2200                                 {
2201                                         s2 = strchr(s+1, '\\');
2202                                         if (!s2)
2203                                                 break;
2204                                         s = s2;
2205                                 }
2206                                 if (s)
2207                                 {
2208                                         *s = '\0';
2209                                         strcpy(progssrcname, s+1);
2210                                 }
2211                                 else
2212                                         strcpy(progssrcname, filename);
2213                         }
2214                         else
2215                         {
2216                                 MessageBox(NULL, "You didn't select a file", "Error", 0);
2217                                 return 0;
2218                         }
2219                         SetCurrentDirectory(progssrcdir);
2220                         *progssrcdir = '\0';
2221                 }
2222         }
2223
2224         resetprogssrc = true;
2225
2226     wndclass.style      = 0;
2227     wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;
2228     wndclass.cbClsExtra    = 0;
2229     wndclass.cbWndExtra    = 0;
2230     wndclass.hInstance     = ghInstance;
2231     wndclass.hIcon         = 0;
2232     wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
2233         wndclass.hbrBackground = (void *)COLOR_WINDOW;
2234     wndclass.lpszMenuName  = 0;
2235     wndclass.lpszClassName = MDI_WINDOW_CLASS_NAME;
2236         RegisterClass(&wndclass);
2237
2238         mainwindow=CreateWindow(MDI_WINDOW_CLASS_NAME, "FTE QuakeC compiler", WS_OVERLAPPEDWINDOW,
2239                 0, 0, 640, 480, NULL, NULL, ghInstance, NULL);
2240
2241         if (mdibox)
2242         {
2243                 SetWindowText(mainwindow, "FTE QuakeC Development Suite");
2244         }
2245
2246         if (!mainwindow)
2247         {
2248                 MessageBox(NULL, "Failed to create main window", "Error", 0);
2249                 return 0;
2250         }
2251
2252         InitCommonControls();
2253 /*
2254         outputbox=CreateWindowEx(WS_EX_CLIENTEDGE,
2255                 "EDIT",
2256                 "",
2257                 WS_CHILD | ES_READONLY | WS_VISIBLE | 
2258                 WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
2259                 ES_MULTILINE | ES_AUTOVSCROLL,
2260                 0, 0, 0, 0,
2261                 mainwindow,
2262                 NULL,
2263                 ghInstance,
2264                 NULL);
2265 */
2266
2267         if (!mdibox)
2268                 outputbox = CreateAnEditControl(mainwindow);
2269
2270         for (i = 0; i < NUMBUTTONS; i++)
2271         {
2272                 buttons[i].hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
2273                         "BUTTON",
2274                         buttons[i].text,
2275                         WS_CHILD | WS_VISIBLE,
2276                         0, 0, 5, 5,
2277                         mainwindow,
2278                         (HMENU)(i+1),
2279                         ghInstance,
2280                         NULL); 
2281         }
2282
2283         ShowWindow(mainwindow, SW_SHOWDEFAULT);
2284
2285         if (fl_compileonstart)
2286         {
2287                 CreateOutputWindow();
2288                 RunCompiler(lpCmdLine);
2289         }
2290         else
2291         {
2292                 if (mdibox)
2293                 {
2294                         buttons[ID_EDIT].washit = true;
2295                 }
2296                 else
2297                 {
2298                         GUIprintf("Welcome to FTE QCC\n");
2299                         GUIprintf("Source file: ");
2300                         GUIprintf(progssrcname);
2301                         GUIprintf("\n");
2302
2303                         RunCompiler("-?");
2304                 }
2305         }
2306
2307         while(mainwindow || editors)
2308         {
2309                 MSG        msg;
2310
2311                 if (resetprogssrc)
2312                 {       //this here, with the compiler below, means that we don't run recursivly.
2313                         resetprogssrc = false;
2314                         SetProgsSrc();
2315                 }
2316
2317                 EditorsRun();
2318
2319                 while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
2320                 {
2321                         if (!GetMessage (&msg, NULL, 0, 0))
2322                                 break;
2323                         if (!mdibox || !TranslateMDISysAccel(mdibox, &msg))
2324                         { 
2325                                 TranslateMessage (&msg);
2326                                 DispatchMessage (&msg);
2327                         }
2328                 }
2329
2330                 if (mainwindow)
2331                 {
2332                         i = Edit_GetSel(outputbox);
2333                         if ((i>>16) != (i&0xffff) && i != -1)   //some text is selected.
2334                         {
2335                                 int bytes;
2336                                 char line[1024];
2337                                 char *colon1, *colon2 = NULL;
2338
2339                                 int l1;
2340                                 int l2;
2341
2342                                 l1 = Edit_LineFromChar(outputbox, i&0xffff);
2343                                 l2 = Edit_LineFromChar(outputbox, (i>>16)&0xffff);
2344                                 if (l1 == l2)
2345                                 {
2346                                         bytes = Edit_GetLine(outputbox, Edit_LineFromChar(outputbox, i&0xffff), line, sizeof(line)-1);
2347                                         line[bytes] = 0;
2348
2349                                         for (colon1 = line+strlen(line)-1; *colon1 <= ' ' && colon1>=line; colon1--)
2350                                                 *colon1 = '\0';
2351                                         if (!strncmp(line, "warning: ", 9))
2352                                                 memmove(line, line+9, sizeof(line));
2353                                         colon1=line;
2354                                         do
2355                                         {
2356                                                 colon1 = strchr(colon1+1, ':');
2357                                         } while (colon1 && colon1[1] == '\\');
2358
2359                                         if (colon1)
2360                                         {
2361                                                 colon2 = strchr(colon1+1, ':');
2362                                                 while (colon2 && colon2[1] == '\\')
2363                                                 {
2364                                                         colon2 = strchr(colon2+1, ':');
2365                                                 }
2366                                                 if (colon2)
2367                                                 {
2368                                                         *colon1 = '\0';
2369                                                         *colon2 = '\0';
2370                                                         EditFile(line, atoi(colon1+1)-1);
2371                                                 }
2372                                                 else if (!strncmp(line, "Source file: ", 13))
2373                                                         EditFile(line+13, -1);
2374                                                 else if (!strncmp(line, "Including: ", 11))
2375                                                         EditFile(line+11, -1);
2376                                         }
2377                                         else if (!strncmp(line, "compiling ", 10))
2378                                                 EditFile(line+10, -1);
2379                                         else if (!strncmp(line, "prototyping ", 12))
2380                                                 EditFile(line+12, -1);
2381                                         Edit_SetSel(outputbox, i&0xffff, i&0xffff);     //deselect it.
2382                                 }
2383                         }
2384
2385                         if (buttons[ID_COMPILE].washit)
2386                         {
2387                                 CreateOutputWindow();
2388                                 RunCompiler(parameters);
2389
2390                                 buttons[ID_COMPILE].washit = false;
2391                         }
2392                         if (buttons[ID_EDIT].washit)
2393                         {
2394                                 buttons[ID_EDIT].washit = false;
2395                                 EditFile(progssrcname, -1);
2396                         }
2397                         if (buttons[ID_OPTIONS].washit)
2398                         {
2399                                 buttons[ID_OPTIONS].washit = false;
2400                                 OptionsDialog();
2401                         }
2402                         if (buttons[ID_QUIT].washit)
2403                         {
2404                                 buttons[ID_QUIT].washit = false;
2405                                 DestroyWindow(mainwindow);
2406                         }
2407                 }
2408
2409                 if (*finddef)
2410                 {
2411                         GoToDefinition(finddef);
2412                         *finddef = '\0';
2413                 }
2414
2415                 Sleep(10);
2416         }
2417
2418         return 0;
2419 }