Initial Commit
[packages] / xemacs-packages / oo-browser / tree-w32 / intf-msw.c
1 #include <windows.h>
2
3 #include <commctrl.h>
4
5 #include <commdlg.h>
6
7 #include <stdlib.h>
8
9
10
11 #include "resource.h"
12
13 #include "dbl.h"
14
15 #include "intf.h"
16
17 #include "tree.h"
18
19 #include "input.h"
20
21
22
23
24
25 /*
26
27  * Globals 
28
29  */
30
31
32
33 char         *ProgramName = "oobr";
34
35
36
37 int           TreeContourWidth = 1;
38
39 int           TreeBorderSize = BORDER_SIZE;
40
41 int           TreeParentDistance = PARENT_DISTANCE;
42
43 DoubleBuffer *TreeDrawingAreaDB;
44
45 ContourOption TreeShowContourOption = NoContours;
46
47 DensityOption TreeLayoutDensity = Fixed;
48
49 char          TreeShowSteps =  FALSE;
50
51 char          TreeAlignNodes = FALSE;
52
53 char          PauseAfterStep    = FALSE;
54
55
56
57
58
59 HWND hwndFrame, hwndClient;
60
61
62
63 static const char* SZ_FRAME_CLASS = "OObrFrameClass";
64
65 static const char* SZ_CLIENT_CLASS = "OObrClientClass";
66
67 static HWND hwndStatus;
68
69 static HINSTANCE hAppInst;
70
71
72
73 static BOOL FileModified = FALSE;
74
75 static char CurrentFile [MAX_PATH];
76
77 static char NextFile [MAX_PATH];
78
79 static char NewNodeName [MAX_NODE_NAME_LENGHT];
80
81 static char *FileTitle = NULL;
82
83
84
85 /* The semantics for these is different than in X. 
86
87    Selected node is the one selected with left click.
88
89    Popup node is the tempoparily highlighted one, by a
90
91    right click, only while a popup menu is active */
92
93 static Tree *SelectedNode;
94
95 static Tree *PopupNode;
96
97
98
99 /*
100
101  * Prototypes
102
103  */
104
105 BOOL LoadFile (void);
106
107 BOOL SaveFileAs (void);
108
109 BOOL SaveFile (void);
110
111 void UpdateFrameTitle (void);
112
113 BOOL PromptFileName (BOOL bSave);
114
115 UINT FileMessage (UINT idstr, char* file, UINT flags);
116
117
118
119 /*
120
121  * ------------------------------------
122
123  * File handling
124
125  * ------------------------------------
126
127  */
128
129
130
131 static void
132
133 SetupInterface ()
134
135 {
136
137   UpdateFrameTitle ();
138
139
140
141   PopupNode = NULL;
142
143   SelectedNode = NULL;
144
145   SetWindowOrgEx (TreeDrawingAreaDB->hdc, 0, 0, NULL);
146
147
148
149   InvalidateRect (hwndClient, NULL, TRUE);
150
151 }
152
153
154
155 static BOOL
156
157 NewFile (void)
158
159 {
160
161   CurrentFile[0] = '\0';
162
163   FileTitle = NULL;
164
165   SetupInterface ();
166
167   FileModified = TRUE;
168
169
170
171   if (TheTree)
172
173     Delete (TheTree);
174
175   TheTree = MakeNode();
176
177   SetNodeLabel(TheTree, strdup (NewNodeName));
178
179   SetupTree(TheTree);
180
181
182
183   return TRUE;
184
185 }
186
187
188
189 static BOOL
190
191 LoadFile (void)
192
193 {
194
195   Tree* newTree;
196
197   ErrCode error;
198
199
200
201   /* Save file under the name in NextFile,
202
203      as set by PromptFileName */
204
205   newTree = ReadTreeFromFile (NextFile, &error);
206
207   
208
209   if (error != ERR_NONE)
210
211     {
212
213       if (newTree)
214
215         Delete (newTree);
216
217       FileMessage (IDS_ERRORFIRST + error, NextFile,
218
219                    MB_OK | MB_ICONEXCLAMATION);
220
221       return FALSE;
222
223     }
224
225
226
227   strcpy (CurrentFile, NextFile);
228
229   SetupInterface ();
230
231   FileModified = FALSE;
232
233
234
235   if (TheTree)
236
237     Delete (TheTree);
238
239   TheTree = newTree;
240
241   SetupTree (newTree);
242
243
244
245   return TRUE;
246
247 }
248
249
250
251 static BOOL
252
253 SaveFileAs (void)
254
255 {
256
257   if (!PromptFileName (TRUE))
258
259     return FALSE;
260
261
262
263   /* Save file under the name in NextFile,
264
265      as set by PromptFileName */
266
267   if (!SaveTreeToFile (TheTree, NextFile))
268
269     {
270
271       FileMessage (IDS_ERRORFIRST + ERR_OPENFAIL, NextFile,
272
273                    MB_OK | MB_ICONEXCLAMATION);
274
275       return FALSE;
276
277     }
278
279
280
281   strcpy (CurrentFile, NextFile);
282
283   UpdateFrameTitle ();
284
285   FileModified = FALSE;
286
287 }
288
289
290
291 static BOOL
292
293 SaveFile (void)
294
295 {
296
297   /* Always ask for filename if currently untitled */
298
299   if (CurrentFile[0] == 0)
300
301     return SaveFileAs ();
302
303
304
305   if (!SaveTreeToFile (TheTree, CurrentFile))
306
307     {
308
309       FileMessage (IDS_ERRORFIRST + ERR_OPENFAIL, CurrentFile,
310
311                    MB_OK | MB_ICONEXCLAMATION);
312
313       return FALSE;
314
315     }
316
317
318
319   FileModified = FALSE;
320
321   return TRUE;
322
323 }
324
325
326
327 /* 
328
329  * Set frame title to either "FILE : OObrowser" or "OObrowser",
330
331  * depending on whether a file is open
332
333  */
334
335 static void
336
337 UpdateFrameTitle (void)
338
339 {
340
341   char buf [MAX_PATH + 4], *p;
342
343   
344
345   if (FileTitle == NULL || FileTitle[0] == '\0')
346
347     LoadString (hAppInst, IDS_UNTITLED, buf, sizeof(buf));
348
349   else
350
351     strcpy (buf, FileTitle);
352
353
354
355   strcat (buf, " - ");
356
357   p = buf + strlen (buf);
358
359
360
361   LoadString (hAppInst, IDS_APPTITLE, p,
362
363               sizeof (buf) - (p - buf));
364
365   SetWindowText (hwndFrame, buf);
366
367 }
368
369
370
371 /*
372
373  *
374
375  */
376
377 static UINT
378
379 FileMessage (UINT idstr, char* file, UINT flags)
380
381 {
382
383   char buf [MAX_PATH + 128], format [128], title[64];
384
385
386
387   LoadString (hAppInst, IDS_APPTITLE, title, sizeof(title));
388
389   LoadString (hAppInst, idstr, format, sizeof(format));
390
391   wsprintf (buf, format, file);
392
393
394
395   return MessageBox (hwndFrame, buf, title, flags);
396
397 }
398
399
400
401 /*
402
403  * Propmt for file name for save or load. Return TRUE if user has
404
405  * chosen a name, FALSE if canceled. If name is chosen, it is
406
407  * stored into NextFile, and its title part into FileTitle
408
409  */
410
411 static BOOL
412
413 PromptFileName (BOOL bSave)
414
415 {
416
417   OPENFILENAME ofn;
418
419   BOOL ok;
420
421
422
423   if (bSave)
424
425     {
426
427       /* Default to current file name */
428
429       strcpy (NextFile, CurrentFile);
430
431     }
432
433   else
434
435     {
436
437       /* Start with empty file name */
438
439       *NextFile = 0;
440
441     }
442
443
444
445   ofn.lStructSize = sizeof (ofn);
446
447   ofn.hwndOwner = hwndFrame;
448
449   ofn.lpstrFilter = NULL; /* #### */
450
451   ofn.lpstrCustomFilter = NULL;
452
453   ofn.lpstrFile = NextFile;
454
455   ofn.nMaxFile = sizeof (NextFile);
456
457   ofn.lpstrFileTitle = NULL;
458
459   ofn.lpstrInitialDir = NULL;
460
461   ofn.lpstrTitle = NULL;
462
463   ofn.Flags = (bSave
464
465                ? OFN_OVERWRITEPROMPT | OFN_NOTESTFILECREATE
466
467                : OFN_FILEMUSTEXIST);
468
469   ofn.lpstrDefExt = NULL;
470
471   ofn.lCustData = 0;
472
473   ofn.lpfnHook = NULL;
474
475   ofn.lpTemplateName = NULL;
476
477
478
479   ok = (bSave
480
481         ? GetSaveFileName (&ofn)
482
483         : GetOpenFileName (&ofn));
484
485   if (ok)
486
487     FileTitle = NextFile + ofn.nFileOffset;
488
489
490
491   return ok;
492
493 }
494
495
496
497 /*
498
499  * Dialog procedure for the node name editing  dialog
500
501  */
502
503 static BOOL CALLBACK
504
505 DlgNodeNameProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
506
507 {
508
509   switch (uMsg)
510
511     {
512
513     case WM_INITDIALOG:
514
515       /* lParam is TRUE for new root node when creating the tree,
516
517          FALSE for node name editing. We show different caption
518
519          based on this flag. */
520
521       {
522
523         char buf [128];
524
525         LoadString (hAppInst, lParam ? IDS_ROOTNODE : IDS_MERENODE,
526
527                     buf, sizeof (buf));
528
529         SetWindowText (hwnd, buf);
530
531         SetDlgItemText (hwnd, IDC_NAME, NewNodeName);
532
533       }
534
535       break;
536
537
538
539     case WM_COMMAND:
540
541       switch (LOWORD(wParam))
542
543         {
544
545         case IDOK:
546
547           GetDlgItemText (hwnd, IDC_NAME, NewNodeName, sizeof(NewNodeName));
548
549           EndDialog (hwnd, TRUE);
550
551           break;
552
553
554
555         case IDCANCEL:
556
557           EndDialog (hwnd, FALSE);
558
559           break;
560
561         }
562
563       break;
564
565
566
567     default:
568
569       return FALSE;
570
571     }
572
573   return TRUE;
574
575 }
576
577
578
579 /*
580
581  * Dialog procedure for the spacing dialog
582
583  */
584
585 static BOOL CALLBACK
586
587 DlgSpacingProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
588
589 {
590
591   switch (uMsg)
592
593     {
594
595     case WM_INITDIALOG:
596
597       SendDlgItemMessage (hwnd, IDC_LEVEL_SL, TBM_SETRANGE, FALSE, MAKELONG (10, 50));
598
599       SendDlgItemMessage (hwnd, IDC_LEVEL_SL, TBM_SETPOS, TRUE, TreeParentDistance);
600
601       SetDlgItemInt (hwnd, IDC_LEVEL_ED, TreeParentDistance, FALSE);
602
603
604
605       SendDlgItemMessage (hwnd, IDC_SIBLING_SL, TBM_SETRANGE, FALSE, MAKELONG (1, 15));
606
607       SendDlgItemMessage (hwnd, IDC_SIBLING_SL, TBM_SETPOS, TRUE, TreeBorderSize);
608
609       SetDlgItemInt (hwnd, IDC_SIBLING_ED, TreeBorderSize, FALSE);
610
611       break;
612
613
614
615     case WM_COMMAND:
616
617       switch (LOWORD(wParam))
618
619         {
620
621         case IDOK:
622
623           {
624
625             int NewLevel = SendDlgItemMessage (hwnd, IDC_LEVEL_SL, TBM_GETPOS, 0, 0);
626
627             int NewSibling = SendDlgItemMessage (hwnd, IDC_SIBLING_SL, TBM_GETPOS, 0, 0);
628
629             if (NewLevel != TreeParentDistance
630
631                 || NewSibling != TreeBorderSize)
632
633               {
634
635                 TreeParentDistance = NewLevel;
636
637                 TreeBorderSize = NewSibling;
638
639                 if (TheTree)
640
641                   {
642
643                     DeleteTree(TheTree, TRUE);
644
645                     if (TreeAlignNodes)
646
647                       ResetLabels(TheTree);
648
649                     SetupTree(TheTree);
650
651                     InvalidateRect (hwndClient, NULL, TRUE);
652
653                   }
654
655               }
656
657           }
658
659           EndDialog (hwnd, TRUE);
660
661           break;
662
663
664
665         case IDCANCEL:
666
667           EndDialog (hwnd, FALSE);
668
669           break;
670
671         }
672
673       break;
674
675
676
677     case WM_HSCROLL:
678
679       SetDlgItemInt (hwnd, IDC_LEVEL_ED,
680
681         SendDlgItemMessage (hwnd, IDC_LEVEL_SL, TBM_GETPOS, 0, 0), FALSE);
682
683       SetDlgItemInt (hwnd, IDC_SIBLING_ED,
684
685         SendDlgItemMessage (hwnd, IDC_SIBLING_SL, TBM_GETPOS, 0, 0), FALSE);
686
687       break;
688
689
690
691     default:
692
693       return FALSE;
694
695     }
696
697   return TRUE;
698
699 }
700
701    
702
703 /*
704
705  * Dialog procedure for the about dialog
706
707  */
708
709 static BOOL CALLBACK
710
711 DlgAboutProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
712
713 {
714
715   if (uMsg == WM_COMMAND && LOWORD(wParam) == IDOK)
716
717     {
718
719       EndDialog (hwnd, 0);
720
721       return TRUE;
722
723     }
724
725   return FALSE;
726
727 }
728
729
730
731 /*
732
733  * Edit node name given in NAME. Returns pointer to the
734
735  * new name static buffer, or NULL if canceled. The ROOT
736
737  * parameter affects dialog title only
738
739  */
740
741 char*
742
743 DlgNodeName (const char* name, BOOL root)
744
745 {
746
747   if (name)
748
749     strcpy (NewNodeName, name);
750
751   else
752
753     *NewNodeName = 0;
754
755
756
757   return (DialogBoxParam (hAppInst, MAKEINTRESOURCE (IDD_NODENAME), 
758
759                           hwndFrame, DlgNodeNameProc, root)
760
761           ? NewNodeName : NULL);
762
763 }
764
765
766
767 static BOOL
768
769 PromptRootNode (int u_n_u_s_e_d)
770
771 {
772
773   return DlgNodeName (NULL, TRUE) != 0;
774
775 }
776
777
778
779 static BOOL
780
781 PromptAndSave (BOOL (*proc)(int), int param)
782
783 {
784
785   if (proc && !proc (param))
786
787     return FALSE;
788
789
790
791   if (FileModified)
792
793     {
794
795       char buf[80], *p;
796
797       UINT uRes;
798
799
800
801       /* Substitute "Untitled" if no file */
802
803       if (CurrentFile[0])
804
805         p = CurrentFile;
806
807       else
808
809         {
810
811           LoadString (hAppInst, IDS_UNTITLED, buf, sizeof(buf));
812
813           p = buf;
814
815         }
816
817
818
819       uRes = FileMessage (IDS_SAVECHANGES, p, MB_YESNOCANCEL | MB_ICONQUESTION);
820
821       if (uRes == IDCANCEL)
822
823         return FALSE;
824
825       if (uRes == IDNO)
826
827         return TRUE;
828
829
830
831       return SaveFile ();
832
833     }
834
835   else
836
837     return TRUE;
838
839 }
840
841
842
843 static void
844
845 MaybeNewTreeNode (Tree* node, NodePosition pos)
846
847 {
848
849   char *newName = DlgNodeName (NULL, FALSE);
850
851   if (newName)
852
853     {
854
855       InsertNode (node, pos, strdup (newName));
856
857       InvalidateRect (hwndClient, NULL, TRUE);
858
859       FileModified = TRUE;
860
861     }
862
863 }
864
865
866
867 static void
868
869 SelectNode (Tree* node, BOOL edit)
870
871 {    
872
873   /* Redraw old node in un-selected state */
874
875   if (SelectedNode != NULL)
876
877     {
878
879       SelectedNode->highlight = FALSE;
880
881       SelectedNode->focus = FALSE;
882
883       DrawNode (SelectedNode, New);
884
885     }
886
887
888
889   SelectedNode = node;
890
891
892
893   if (node)
894
895     {
896
897     
898
899       printf ("%s^^%s^^%s\n", 
900
901               CurrentFile,
902
903               edit ? "br-edit" : "br-view",
904
905               (SelectedNode->value) ? SelectedNode->value : SelectedNode->label.text);
906
907
908
909       StatusMsg (SelectedNode->label.text, 1);
910
911     
912
913       /* Redraw new node in selected state */
914
915       SelectedNode->highlight = TRUE;
916
917       SelectedNode->focus = TRUE;
918
919       DrawNode(SelectedNode, New);
920
921     }
922
923   else
924
925     StatusMsg ("", 1);
926
927 }
928
929
930
931 static void
932
933 ChangeFontMaybe (void)
934
935 {
936
937   CHOOSEFONT cf;
938
939   LOGFONT lf;
940
941
942
943   cf.lStructSize = sizeof (cf);
944
945   cf.hwndOwner = hwndFrame;
946
947   cf.lpLogFont = &lf;
948
949   cf.Flags = (CF_FORCEFONTEXIST | CF_NOSIMULATIONS | CF_NOVECTORFONTS
950
951               | CF_SELECTSCRIPT | CF_NOVERTFONTS | CF_SCREENFONTS);
952
953
954
955   if (ChooseFont (&cf) && SetNewFont (&lf))
956
957     {
958
959       DeleteTree(TheTree, TRUE);
960
961       ResetLabels(TheTree);
962
963       SetupTree(TheTree);
964
965       InvalidateRect (hwndClient, NULL, TRUE);
966
967     }
968
969 }
970
971
972
973
974
975 /*
976
977  * Menu command handlers
978
979  */
980
981 static void
982
983 HandleClientMenuCommand (WORD wId)
984
985 {
986
987   switch (wId)
988
989     {
990
991     case ID_EDIT_ADDCHILD:
992
993       MaybeNewTreeNode (PopupNode, Child);
994
995       break;
996
997
998
999     case ID_EDIT_ADDSIBLINGBEFORE:
1000
1001       MaybeNewTreeNode (PopupNode, Before);
1002
1003       break;
1004
1005
1006
1007     case ID_EDIT_ADDSIBLIBNGAFTER:
1008
1009       MaybeNewTreeNode (PopupNode, After);
1010
1011       break;
1012
1013
1014
1015     case ID_EDIT_DELETE:
1016
1017       SelectNode(NULL, FALSE); /* deselect node before deleting it! */
1018
1019       DeleteNode(PopupNode);
1020
1021       InvalidateRect (hwndClient, NULL, TRUE);
1022
1023       FileModified = TRUE;
1024
1025       break;
1026
1027
1028
1029     case ID_VIEW_COLLAPSE:
1030
1031     case ID_VIEW_EXPAND:
1032
1033       ExpandCollapseNode(PopupNode);
1034
1035       InvalidateRect (hwndClient, NULL, TRUE);
1036
1037       break;
1038
1039
1040
1041     case ID_VIEW_SPACING:
1042
1043       DialogBox (hAppInst, MAKEINTRESOURCE (IDD_SPACING), hwndFrame, DlgSpacingProc);
1044
1045       break;
1046
1047
1048
1049     case ID_VIEW_FONT:
1050
1051       ChangeFontMaybe ();
1052
1053       break;
1054
1055
1056
1057     case ID_VIEW_ALIGNLEVEL:
1058
1059       TreeAlignNodes = !TreeAlignNodes;
1060
1061       DeleteTree(TheTree, TRUE);
1062
1063       ResetLabels(TheTree);
1064
1065       SetupTree(TheTree);
1066
1067       InvalidateRect (hwndClient, NULL, TRUE);
1068
1069       break;
1070
1071
1072
1073     case ID_POPUP_EDIT:
1074
1075       SelectNode (PopupNode, TRUE);
1076
1077       break;
1078
1079
1080
1081     case ID_POPUP_VIEW:
1082
1083       SelectNode (PopupNode, FALSE);
1084
1085       break;
1086
1087     }
1088
1089 }
1090
1091
1092
1093 static BOOL
1094
1095 HandleFrameMenuCommand (WORD wId)
1096
1097 {
1098
1099   switch (wId)
1100
1101     {
1102
1103     case ID_FILE_NEW:
1104
1105       if (PromptAndSave (PromptRootNode, 0))
1106
1107         NewFile ();
1108
1109       break;
1110
1111
1112
1113     case ID_FILE_OPEN:
1114
1115       if (PromptAndSave (PromptFileName, FALSE))
1116
1117         LoadFile ();
1118
1119       break;
1120
1121
1122
1123     case ID_FILE_SAVE:
1124
1125       SaveFile ();
1126
1127       break;
1128
1129
1130
1131     case ID_FILE_SAVEAS:
1132
1133       SaveFileAs ();
1134
1135       break;
1136
1137
1138
1139     case ID_FILE_EXIT:
1140
1141       if (PromptAndSave (NULL, 0))
1142
1143         DestroyWindow (hwndFrame);
1144
1145       break;
1146
1147
1148
1149     case ID_HELP_CONTENTS:
1150
1151       WinHelp (hwndFrame, "oobr.hlp", HELP_CONTENTS, 0);
1152
1153       break;
1154
1155
1156
1157     case ID_HELP_ABOUT:
1158
1159       DialogBox (hAppInst, MAKEINTRESOURCE (IDD_ABOUT), hwndFrame, DlgAboutProc);
1160
1161       break;
1162
1163
1164
1165     default:
1166
1167       return FALSE;
1168
1169     }
1170
1171   return TRUE;
1172
1173 }
1174
1175
1176
1177 static void
1178
1179 HandleScroll (HWND hwnd, int dir, int op, int newpos)
1180
1181 {
1182
1183   SCROLLINFO si;
1184
1185   POINT pt;
1186
1187   int oldpos, maxpos;
1188
1189
1190
1191   /* Get scroll metrics */
1192
1193   si.cbSize = sizeof (si);
1194
1195   si.fMask = SIF_ALL;
1196
1197   GetScrollInfo (hwnd, dir, &si);
1198
1199
1200
1201   /* Determine old position */
1202
1203   GetWindowOrgEx (TreeDrawingAreaDB->hdc, &pt);
1204
1205   oldpos = dir == SB_VERT ? pt.y : pt.x;
1206
1207   maxpos = si.nMax - si.nPage - 1;
1208
1209
1210
1211   switch (op)
1212
1213     {
1214
1215     case SB_TOP:
1216
1217       newpos = 0;
1218
1219       break;
1220
1221     case SB_BOTTOM:
1222
1223       newpos = maxpos;
1224
1225       break;
1226
1227     case SB_PAGEUP:
1228
1229       newpos = oldpos - 3 * si.nPage / 4;
1230
1231       break;
1232
1233     case SB_PAGEDOWN:
1234
1235       newpos = oldpos + 3 * si.nPage / 4;
1236
1237       break;
1238
1239     case SB_LINEUP:
1240
1241       newpos = oldpos - 16;
1242
1243       break;
1244
1245     case SB_LINEDOWN:
1246
1247       newpos = oldpos + 16;
1248
1249       break;
1250
1251     case SB_ENDSCROLL:
1252
1253       return;
1254
1255     }
1256
1257   
1258
1259   newpos = max (newpos, 0);
1260
1261   newpos = min (newpos, maxpos);
1262
1263
1264
1265   if (newpos == oldpos)
1266
1267     return;
1268
1269
1270
1271   *(dir == SB_VERT ? &pt.y : &pt.x) = newpos;
1272
1273   SetWindowOrgEx (TreeDrawingAreaDB->hdc, pt.x, pt.y, NULL);
1274
1275   ScrollWindow (hwnd,
1276
1277                 dir == SB_VERT ? 0 : oldpos - newpos,
1278
1279                 dir != SB_VERT ? 0 : oldpos - newpos,
1280
1281                 NULL, NULL);
1282
1283   SetScrollPos (hwnd, dir, newpos, TRUE);
1284
1285 }
1286
1287
1288
1289 static POINT
1290
1291 ToLP (LPARAM lParam)
1292
1293 {
1294
1295   POINT pt;
1296
1297   pt.x = LOWORD (lParam);
1298
1299   pt.y = HIWORD (lParam);
1300
1301   DPtoLP (TreeDrawingAreaDB->hdc, &pt, 1);
1302
1303   return pt;
1304
1305 }
1306
1307
1308
1309 static void
1310
1311 HandleLButton (POINT pt, BOOL edit)
1312
1313 {
1314
1315   Tree *node;
1316
1317   if (SearchTree(TheTree, pt.x, pt.y, &node))
1318
1319     SelectNode (node, edit);
1320
1321   else
1322
1323     SelectNode (NULL, edit);
1324
1325 }
1326
1327
1328
1329 static void
1330
1331 HandleRButton (POINT ptLP, POINT ptClick)
1332
1333 {
1334
1335   Tree *node;
1336
1337   if (SearchTree(TheTree, ptLP.x, ptLP.y, &node))
1338
1339     {
1340
1341       HMENU hMenu, hPopup;
1342
1343     
1344
1345       PopupNode = node;
1346
1347
1348
1349       if (SelectedNode != PopupNode)
1350
1351         {
1352
1353           PopupNode->highlight = TRUE;
1354
1355           DrawNode(PopupNode, New);
1356
1357           if (SelectedNode)
1358
1359             {
1360
1361               SelectedNode->highlight = FALSE;
1362
1363               DrawNode(SelectedNode, New);
1364
1365             }
1366
1367         }
1368
1369
1370
1371       hMenu = LoadMenu (hAppInst, MAKEINTRESOURCE (IDR_NODEPOPUP));
1372
1373       hPopup = GetSubMenu (hMenu, 0);
1374
1375
1376
1377       TrackPopupMenu (hPopup, TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1378
1379                       ptClick.x, ptClick.y, 0, hwndClient, NULL);
1380
1381
1382
1383       DestroyMenu (hMenu);
1384
1385
1386
1387       if (SelectedNode != PopupNode)
1388
1389         {
1390
1391           PopupNode->highlight = FALSE;
1392
1393           DrawNode(PopupNode, New);
1394
1395           if (SelectedNode)
1396
1397             {
1398
1399               SelectedNode->highlight = TRUE;
1400
1401               DrawNode(SelectedNode, New);
1402
1403             }
1404
1405         }
1406
1407     }
1408
1409 }
1410
1411
1412
1413 static void
1414
1415 HandleMenuPopup (HMENU hMenu)
1416
1417 {
1418
1419 #define FROB(item,cond) EnableMenuItem (hMenu, (item), MF_BYCOMMAND | ((cond) ? MF_GRAYED : 0));
1420
1421
1422
1423   FROB (ID_FILE_SAVE, TheTree == NULL);
1424
1425   FROB (ID_FILE_SAVEAS, TheTree == NULL);
1426
1427   FROB (ID_VIEW_EXPAND, PopupNode == NULL || !PopupNode->elision || IS_LEAF(PopupNode));
1428
1429   FROB (ID_VIEW_COLLAPSE, PopupNode == NULL || PopupNode->elision || IS_LEAF(PopupNode));
1430
1431   FROB (ID_FILE_SAVEAS, TheTree == NULL);
1432
1433   FROB (ID_VIEW_ALIGNLEVEL, TheTree == NULL);
1434
1435  
1436
1437 #undef FROB
1438
1439   
1440
1441   CheckMenuItem (hMenu, ID_VIEW_ALIGNLEVEL, MF_BYCOMMAND | (TreeAlignNodes ? MF_CHECKED : 0));
1442
1443 }
1444
1445
1446
1447 /*
1448
1449  * Client window procedure
1450
1451  */
1452
1453 static LRESULT CALLBACK
1454
1455 ClientWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1456
1457 {
1458
1459   switch (uMsg)
1460
1461     {
1462
1463     case WM_CREATE:
1464
1465       /* We really need that very early. Scrollbar setup depends on this */
1466
1467       hwndClient = hwnd;
1468
1469       TreeDrawingAreaDB = DBLcreate_double_buffer ();
1470
1471       break;
1472
1473
1474
1475     case WM_PAINT:
1476
1477       {
1478
1479         PAINTSTRUCT ps;
1480
1481         BeginPaint (hwnd, &ps);
1482
1483         ExposeHandler ();
1484
1485         EndPaint (hwnd, &ps);
1486
1487       }
1488
1489       break;
1490
1491
1492
1493     case WM_SIZE:
1494
1495       if (TreeDrawingAreaDB)
1496
1497         {
1498
1499           int w, h;
1500
1501           GetDrawingSize (&w, &h);
1502
1503           SetDrawingSize (w, h);
1504
1505         }
1506
1507       break;
1508
1509
1510
1511     case WM_MENUSELECT:
1512
1513       {
1514
1515         int zero = 0;
1516
1517         MenuHelp (uMsg, wParam, lParam, NULL, hAppInst, hwndStatus, &zero);
1518
1519       }
1520
1521       break;
1522
1523
1524
1525     case WM_INITMENUPOPUP:
1526
1527       HandleMenuPopup ((HMENU) wParam);
1528
1529       break;
1530
1531
1532
1533     case WM_VSCROLL:
1534
1535       HandleScroll (hwnd, SB_VERT, LOWORD(wParam), HIWORD(wParam));
1536
1537       break;
1538
1539
1540
1541     case WM_HSCROLL:
1542
1543       HandleScroll (hwnd, SB_HORZ, LOWORD(wParam), HIWORD(wParam));
1544
1545       break;
1546
1547
1548
1549     case WM_LBUTTONDOWN:
1550
1551       /* View node command */
1552
1553       HandleLButton (ToLP (lParam), FALSE);
1554
1555       break;
1556
1557
1558
1559     case WM_LBUTTONDBLCLK:
1560
1561       /* Edit node command */
1562
1563       HandleLButton (ToLP (lParam), TRUE);
1564
1565       break;
1566
1567
1568
1569     case WM_RBUTTONDOWN:
1570
1571       /* Pop up the menu */
1572
1573       {
1574
1575         POINT ptClick;
1576
1577         ptClick.x = LOWORD (lParam);
1578
1579         ptClick.y = HIWORD (lParam);
1580
1581         ClientToScreen (hwnd, &ptClick);
1582
1583         HandleRButton (ToLP (lParam), ptClick);
1584
1585       }
1586
1587       break;
1588
1589
1590
1591     case WM_COMMAND:
1592
1593       HandleClientMenuCommand (LOWORD(wParam));
1594
1595       break;
1596
1597
1598
1599     default:
1600
1601       return DefWindowProc (hwnd, uMsg, wParam, lParam);
1602
1603     }
1604
1605   return 0;
1606
1607 }
1608
1609
1610
1611 /*
1612
1613  * Frame window procedure
1614
1615  */
1616
1617 static LRESULT CALLBACK
1618
1619 FrameWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1620
1621 {
1622
1623   switch (uMsg)
1624
1625     {
1626
1627     case WM_CREATE:
1628
1629       /* Create status bar */
1630
1631       hwndStatus = CreateStatusWindow (SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE,
1632
1633                                        NULL, hwnd, 0);
1634
1635       /* Create client window */
1636
1637       hwndClient = CreateWindowEx (WS_EX_CLIENTEDGE, SZ_CLIENT_CLASS, NULL,
1638
1639                                    WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
1640
1641                                    0, 0, 10, 10, /* Adjusted in WM_SIZE handler */
1642
1643                                    hwnd, NULL, hAppInst, NULL);
1644
1645       break;
1646
1647
1648
1649     case WM_DESTROY:
1650
1651       WinHelp (hwndFrame, "oobr.hlp", HELP_QUIT, 0);
1652
1653       PostQuitMessage (0);
1654
1655       break;
1656
1657
1658
1659     case WM_CLOSE:
1660
1661       HandleFrameMenuCommand (ID_FILE_EXIT);
1662
1663       break;
1664
1665
1666
1667     case WM_SIZE:
1668
1669       /* Adjust status bar */
1670
1671       SendMessage (hwndStatus, uMsg, wParam, lParam);
1672
1673       /* Adjust client rectangle */
1674
1675       {
1676
1677         RECT rc;
1678
1679         int delta;
1680
1681         GetClientRect (hwndStatus, &rc);
1682
1683         delta = rc.bottom - rc.top;
1684
1685         GetClientRect (hwnd, &rc);
1686
1687         rc.bottom -= delta;
1688
1689         MoveWindow (hwndClient, rc.left, rc.top,
1690
1691                     rc.right - rc.left, rc.bottom - rc.top, TRUE);
1692
1693       }
1694
1695       break;
1696
1697
1698
1699     case WM_MENUSELECT:
1700
1701       {
1702
1703         int zero = 0;
1704
1705         MenuHelp (uMsg, wParam, lParam, NULL, hAppInst, hwndStatus, &zero);
1706
1707       }
1708
1709       break;
1710
1711
1712
1713     case WM_INITMENUPOPUP:
1714
1715       HandleMenuPopup ((HMENU) wParam);
1716
1717       break;
1718
1719
1720
1721     case WM_COMMAND:
1722
1723       /* Route unhandled command to the client */
1724
1725       if (!HandleFrameMenuCommand (LOWORD(wParam)))
1726
1727         SendMessage (hwndClient, uMsg, wParam, lParam);
1728
1729       break;
1730
1731
1732
1733     case WM_SETFOCUS:
1734
1735       SetFocus (hwndClient);
1736
1737       break;
1738
1739
1740
1741     default:
1742
1743       return DefWindowProc (hwnd, uMsg, wParam, lParam);
1744
1745     }
1746
1747   return 0;
1748
1749 }
1750
1751
1752
1753 /* ----------------------------------------------------------------------------
1754
1755  * 
1756
1757  *   Status() displays the specified text in the status area.
1758
1759  *   'urgent' overrides the value of TreeShowSteps.
1760
1761  * 
1762
1763  * ----------------------------------------------------------------------------
1764
1765  */
1766
1767
1768
1769 void
1770
1771 StatusMsg(char *msg, int urgent)
1772
1773 {
1774
1775   if (TreeShowSteps || urgent) 
1776
1777     SendMessage (hwndStatus, SB_SETTEXT, 0, (LPARAM)msg);
1778
1779 }
1780
1781
1782
1783 /* ----------------------------------------------------------------------------
1784
1785  * 
1786
1787  *  Pause is a trivial function, for the benefit of interface-dependent code
1788
1789  *  inside tree.c. This avoids having to include X11 stuff inside that file.
1790
1791  *  PauseTime is expected to contain an integer indicating 1/10ths of a sec.
1792
1793  * 
1794
1795  * ----------------------------------------------------------------------------
1796
1797  */
1798
1799
1800
1801 void
1802
1803 Pause()
1804
1805 {
1806
1807 }
1808
1809
1810
1811 #ifdef WINDOWED
1812
1813 int WINAPI
1814
1815 WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
1816
1817 {
1818
1819   hAppInst = hInstance;
1820
1821 #else
1822
1823 int
1824
1825 main (int argc, char* argv[])
1826
1827 {
1828
1829   LPTSTR lpCmdLine = argc > 1 ? argv[1] : NULL;
1830
1831   int nCmdShow = SW_SHOWNORMAL;
1832
1833   hAppInst = GetModuleHandle (NULL);
1834
1835 #endif
1836
1837
1838
1839 #ifdef _DEBUG
1840
1841   _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
1842
1843 #endif
1844
1845
1846
1847   InitCommonControls ();
1848
1849
1850
1851   /* Register window classes */
1852
1853   {
1854
1855     WNDCLASS wcl;
1856
1857
1858
1859     /* Frame window class */
1860
1861     wcl.style = 0;
1862
1863     wcl.lpfnWndProc = FrameWndProc;
1864
1865     wcl.cbClsExtra = 0;
1866
1867     wcl.cbWndExtra = 0;
1868
1869     wcl.hInstance = hAppInst;
1870
1871     wcl.hIcon = LoadIcon (hAppInst, MAKEINTRESOURCE (IDI_OOBR));
1872
1873     wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
1874
1875     wcl.hbrBackground = NULL;
1876
1877     wcl.lpszMenuName = MAKEINTRESOURCE (IDR_MAINMENU);
1878
1879     wcl.lpszClassName = SZ_FRAME_CLASS;
1880
1881     RegisterClass (&wcl);
1882
1883
1884
1885     /* Client window class */
1886
1887     wcl.style = CS_OWNDC | CS_DBLCLKS;
1888
1889     wcl.lpfnWndProc = ClientWndProc;
1890
1891     wcl.cbClsExtra = 0;
1892
1893     wcl.cbWndExtra = 0;
1894
1895     wcl.hInstance = hAppInst;
1896
1897     wcl.hIcon = NULL;
1898
1899     wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
1900
1901     wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1902
1903     wcl.lpszMenuName = NULL;
1904
1905     wcl.lpszClassName = SZ_CLIENT_CLASS;
1906
1907     RegisterClass (&wcl);
1908
1909   }
1910
1911
1912
1913   /* Create frame */
1914
1915   hwndFrame = CreateWindowEx (0, SZ_FRAME_CLASS, NULL, WS_OVERLAPPEDWINDOW,
1916
1917                               CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1918
1919                               NULL, NULL, hAppInst, NULL);
1920
1921
1922
1923   /* Show it */
1924
1925   ShowWindow (hwndFrame, nCmdShow);
1926
1927
1928
1929   if (lpCmdLine && lpCmdLine[0])
1930
1931     {
1932
1933       strcpy (NextFile, lpCmdLine);
1934
1935       if (LoadFile ())
1936
1937         FileTitle = strrchr (CurrentFile, '/');
1938
1939         if (FileTitle == NULL)
1940
1941           FileTitle = strrchr (CurrentFile, '\\');
1942
1943         if (FileTitle == NULL)
1944
1945           FileTitle = CurrentFile;
1946
1947     }
1948
1949
1950
1951   UpdateFrameTitle ();
1952
1953
1954
1955   /* Pump messages */
1956
1957   {
1958
1959     MSG msg;
1960
1961     while (GetMessage (&msg, 0, 0, 0))
1962
1963       {
1964
1965         TranslateMessage (&msg);
1966
1967         DispatchMessage (&msg);
1968
1969       }
1970
1971   }
1972
1973
1974
1975   if (TheTree)
1976
1977     Delete (TheTree);
1978
1979
1980
1981   return 0;
1982
1983 }
1984