fsc_window.pro
71.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
; docformat = 'rst'
;
; NAME:
; FSC_Window
;
; PURPOSE:
; Creates a resizeable graphics window for IDL traditional commands (Plot, Contour,
; Surface, etc. or for Coyote Graphics routines, FSC_Plot, FSC_Contour, FSC_Surf, etc.).
; In addition, the window contents can be saved as PostScript files or as raster image
; files. If ImageMagick is installed on your machine, the raster image files can be
; created in very high quality from PostScript files.
;
;******************************************************************************************;
; ;
; Copyright (c) 2011, by Fanning Software Consulting, Inc. All rights reserved. ;
; ;
; Redistribution and use in source and binary forms, with or without ;
; modification, are permitted provided that the following conditions are met: ;
; ;
; * Redistributions of source code must retain the above copyright ;
; notice, this list of conditions and the following disclaimer. ;
; * Redistributions in binary form must reproduce the above copyright ;
; notice, this list of conditions and the following disclaimer in the ;
; documentation and/or other materials provided with the distribution. ;
; * Neither the name of Fanning Software Consulting, Inc. nor the names of its ;
; contributors may be used to endorse or promote products derived from this ;
; software without specific prior written permission. ;
; ;
; THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY ;
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ;
; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT ;
; SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ;
; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;
; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ;
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;
;******************************************************************************************;
;+
; :Description:
; Adds a command object of class IDL_WINDOW_COMMAND to the command list
; maintained by the window.
;
; :Params:
; command: in, required, type=object
; A command object of class IDL_WINDOW_COMMAND.
;-
PRO FSC_CmdWindow::AddCommand, command, INDEX=index
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; If the command is a valid object, add it to the command list.
IF Obj_Valid(command) THEN self.cmds -> Add, command, index, /Before
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; Sends the window commands to a PostScript file.
;
; :Params:
; event: in, required, type=structure
; An event structure.
;-
PRO FSC_CmdWindow::CreatePostScriptFile, event
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; Allow the user to configure the PostScript file.
PS_Start, /GUI, $
CANCEL=cancelled, $
EUROPEAN=self.ps_metric, $
ENCAPSULATED=self.ps_encapsulated, $
SCALE_FACTOR=self.ps_scale_factor, $
CHARSIZE=self.ps_charsize, $
FONT=self.ps_font, $
TT_FONT=self.ps_tt_font
IF cancelled THEN RETURN
; Execute the graphics commands.
self -> ExecuteCommands
; Clean up.
PS_End
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; Deletes a command object from the command list maintained by the window.
;
; :Params:
; cmdIndex: in, optional, type=integer
; The zero-based index of the command to delete. If undefined, the
; index of the last command in the window is used.
;
; :Keywords:
; all: in, optional, type=boolean
; If set, all the commands in the command list are deleted.
;-
PRO FSC_CmdWindow::DeleteCommand, cmdIndex, ALL=all
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; Get the command count.
count = self.cmds -> Get_Count()
; Delete all the commands? Is so, delete and RETURN.
IF Keyword_Set(all) THEN BEGIN
self.cmds -> Delete_Nodes, /DESTROY
self -> ExecuteCommands
RETURN
ENDIF
; Need a command index?
IF N_Elements(cmdIndex) EQ 0 THEN BEGIN
cmdIndex = count - 1
ENDIF
; Do we have a command with this command number?
IF cmdIndex GT (count-1) THEN Message, 'A command with index ' + StrTrim(cmdIndex,2) + ' does not exist.'
IF cmdIndex GE 0 THEN BEGIN
self.cmds -> Delete, cmdIndex, /Destroy
self -> ExecuteCommands
ENDIF ELSE Message, 'A negative command index number is not allowed.'
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; All widget events come here and are dispatched to the proper object method.
;
; :Params:
; event: in, required, type=structure
; An event structure.
;-
PRO FSC_CmdWindow_Dispatch_Events, event
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; Get the window object.
Widget_Control, event.top, GET_UVALUE=self
; Get the event type. If the type is an object, then
; this must be a resize event from the TLB.
Widget_Control, event.id, GET_UVALUE=eventType
IF Obj_Valid(eventType) THEN eventType = 'TLB_RESIZE'
; Dispatch the events to the proper method.
CASE eventType OF
'TLB_RESIZE': self -> Resize, event
'POSTSCRIPT': self -> CreatePostscriptFile, event
ELSE: self -> SaveAsRaster, event
ENDCASE
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method executes the commands on the command list.
;-
PRO FSC_CmdWindow::ExecuteCommands
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
;void = Dialog_Message(!Error_State.MSG)
!P.Multi = thisMulti
IF N_Elements(rr) NE 0 THEN TVLCT, rr, gg, bb
IF (!D.Flags AND 256) NE 0 THEN WSet, -1
RETURN
ENDIF
; Store the current !P.MULTI state.
thisMulti = !P.Multi
thisXOmargin = !X.OMargin
thisYOmargin = !Y.OMargin
; Make this window the current graphics window.
IF (!D.Flags AND 256) NE 0 THEN BEGIN
currentWindow = !D.Window
WSet, self.wid
ENDIF
; Get the current color table vectors so they can be restored.
TVLCT, rr, gg, bb, /GET
; Load the color vectors.
TVLCT, *self.r, *self.g, *self.b
; Erase the window.
IF self.eraseit THEN FSC_Erase, *self.background
; Are we doing multiple commands?
IF Total(self.pmulti) NE 0 THEN !P.Multi = self.pmulti
; How many commands are there?
n_cmds = self.cmds -> Get_Count()
; Issue an informative message if there are no commands to execute.
;IF n_cmds EQ 0 THEN Message, 'There are currently no graphics commands to execute.', /INFORMATIONAL
; Execute the commands.
FOR j=0,n_cmds-1 DO BEGIN
thisCmdObj = self.cmds -> Get_Item(j, /DEREFERENCE)
thisCmdObj -> Draw, SUCCESS=success
; Did you successfully draw this command?
IF ~success THEN BEGIN
thisCmdObj -> List
answer = Dialog_Message('Problem executing the command shown ' + $
'in the console output. Delete command?', /QUESTION)
IF StrUpCase(answer) EQ 'YES' THEN BEGIN
self -> DeleteCommand, j
!P.Multi = thisMulti
!X.OMargin = thisOXmargin
!Y.OMargin = thisOYmargin
IF N_Elements(rr) NE 0 THEN TVLCT, rr, gg, bb
IF (!D.Flags AND 256) NE 0 THEN WSet, -1
RETURN
ENDIF
ENDIF
; Need to delay?
IF self.delay NE 0 THEN Wait, self.delay
ENDFOR
; Restore the colors in effect when we entered.
TVLCT, rr, gg, bb
; Set the !P.Multi and outside margin system variables back to its original values.
!P.Multi = thisMulti
!X.OMargin = thisXOmargin
!Y.OMargin = thisYOmargin
; Reset the current graphics window, if possible.
IF (!D.Flags AND 256) NE 0 THEN BEGIN
IF (currentWindow GE 0) && WindowAvailable(currentWindow) THEN BEGIN
WSet, currentWindow
ENDIF ELSE WSet, -1
ENDIF
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method retrieves properties from the object.
;-
PRO FSC_CmdWindow::GetProperty, $
BACKGROUND=background, $
COLORPALETTE=colorPalette, $
COMMANDS=commands, $
DELAY=delay, $
ERASEIT=eraseit, $
MULTI=multi, $
TLB=tlb, $
WID=wid, $
XOMARGIN=xomargin, $
YOMARGIN=yomargin, $
IM_TRANSPARENT=im_transparent, $ ; Sets the "alpha" keyword on ImageMagick convert command.
IM_DENSITY=im_density, $ ; Sets the density parameter on ImageMagick convert command.
IM_RESIZE=im_resize, $ ; Sets the resize parameter on ImageMagick convert command.
IM_OPTIONS=im_options, $ ; Sets extra ImageMagick options on the ImageMagick convert command.
PS_DELETE=ps_delete, $
PS_ENCAPSULATED=ps_encapsulated, $
PS_METRIC=ps_metric, $
PS_FONT=ps_font, $ ; Select the font for PostScript output.
PS_CHARSIZE=ps_charsize, $ ; Select the character size for PostScript output.
PS_SCALE_FACTOR=ps_scale_factor, $ ; Select the scale factor for PostScript output.
PS_TT_FONT=ps_tt_font ; Select the true-type font to use for PostScript output.
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; Window properties.
IF Arg_Present(background) THEN background = *self.background
IF Arg_Present(colorPalette) THEN BEGIN
len = N_Elements(*self.r)
palette = BytArr(len,3)
palette[*,0] = *self.r
palette[*,1] = *self.g
palette[*,2] = *self.b
colorPalette = palette
ENDIF
IF Arg_Present(commands) THEN commands = self.cmds
IF Arg_Present(delay) THEN delay = self.delay
IF Arg_Present(eraseit) THEN eraseit = self.eraseit
IF Arg_Present(multi) THEN multi = self.pmulti
IF Arg_Present(tlb) THEN tlb = self.tlb
IF Arg_Present(wid) THEN wid = self.wid
IF Arg_Present(xomargin) THEN xomargin = self.xomargin
IF Arg_Present(yomargin) THEN yomargin = self.yomargin
; PostScript properties.
ps_charsize = self.ps_charsize
ps_delete = self.ps_delete
ps_encapsulated = self.ps_encapsulated
ps_metric = self.ps_metric
ps_font = self.ps_font
ps_scale_factor = self.ps_scale_factor
ps_tt_font = self.ps_tt_font
; ImageMagick properties.
im_transparent = self.im_transparent
im_density = self.im_density
im_options = self.im_options
im_resize = self.im_resize
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method lists the command indicated by the command index. In the
; absence of the command index, all commands are listed.
;-
PRO FSC_CmdWindow::ListCommand, cmdIndex
; List the commands in the command window.
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; How many commands are there?
count = self.cmds -> Get_Count()
IF N_Elements(cmdIndex) EQ 0 THEN BEGIN
FOR j = 0, count-1 DO BEGIN
thisCmdObj = self.cmds -> Get_Item(j, /DEREFERENCE)
; Preface the commands with their index number.
thisCmdObj -> List, StrTrim(j,2) + '.'
ENDFOR
ENDIF ELSE BEGIN
IF cmdIndex LT (count-1) THEN BEGIN
thisCmdObj = self.cmds -> Get_Item(cmdIndex, /DEREFERENCE)
; Preface the commands with their index number.
thisCmdObj -> List, StrTrim(cmdIndex,2) + '.'
ENDIF ELSE Message, 'The command index is out of range of the number of commands.'
ENDELSE
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method loads color table vectors into the program.
; The XCOLORS_DATA keyword is required to get color vector
; information from XCOLORS.
;-
PRO FSC_CmdWindow::LoadColors, r, g, b, XCOLORS_DATA=colorData
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; Load the vectors
IF N_Elements(r) NE 0 THEN *self.r = r
IF N_Elements(g) NE 0 THEN *self.g = g
IF N_Elements(b) NE 0 THEN *self.b = b
IF N_Elements(colorData) NE 0 THEN BEGIN
*self.r = colorData.r
*self.g = colorData.g
*self.b = colorData.b
ENDIF
; Execute the commands.
self -> ExecuteCommands
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method replaces a command in the command list. If cmdImdex is missing,
; replace all the commands in the command list.
;-
PRO FSC_CmdWindow::ReplaceCommand, command, cmdIndex, MULTI=multi
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; If cmdIndex is missing, remove all the current commands with this one.
IF N_Elements(cmdIndex) EQ 0 THEN BEGIN
self.cmds -> Delete, /ALL, /Destroy
IF N_Elements(multi) NE 0 THEN BEGIN
self.pmulti = multi ; Reset !P.Multi to new value.
ENDIF ELSE BEGIN
self.pmulti = Intarr(5) ; Reset !P.Multi to zero.
ENDELSE
self.cmds -> Add, command
ENDIF ELSE BEGIN
; Get the old command first, so you can destroy it properly.
oldcmd = self.cmds -> Get_Item(cmdIndex, /DEREFERENCE)
self.cmds -> Replace_Item, cmdIndex, command
Obj_Destroy, oldcmd
ENDELSE
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method resizes the graphics window and executes the commands again.
;-
PRO FSC_CmdWindow::Resize, event
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
Widget_Control, self.drawID, DRAW_XSIZE=event.x, DRAW_YSIZE=event.y
self -> ExecuteCommands
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method saves the graphics window as a raster image file.
;-
PRO FSC_CmdWindow::SaveAsRaster, event
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; On going in here for down event.
IF event.select NE 1 THEN RETURN
Widget_Control, event.ID, Get_UValue=buttonValue
; Determine if this is normal raster (o) or ImageMagick raster (1).
IF StrMid(buttonValue, 0, 6) EQ 'RASTER' THEN BEGIN
fileType = StrMid(buttonValue, 7)
rasterType = 0
ENDIF ELSE BEGIN
filetype = StrMid(buttonValue, 12)
rasterType = 1
ENDELSE
; Make this window the current graphics windows.
currentWindow = !D.Window
WSet, self.wid
; Get a filename from the user.
CASE filetype OF
'BMP': filename = FSC_Pickfile(FILE='fsc_window.bmp', /WRITE, TITLE='Select an Output File...')
'GIF': filename = FSC_Pickfile(FILE='fsc_window.gif', /WRITE, TITLE='Select an Output File...')
'JPEG': filename = FSC_Pickfile(FILE='fsc_window.jpg', /WRITE, TITLE='Select an Output File...')
'PNG': filename = FSC_Pickfile(FILE='fsc_window.png', /WRITE, TITLE='Select an Output File...')
'TIFF': filename = FSC_Pickfile(FILE='fsc_window.tif', /WRITE, TITLE='Select an Output File...')
ENDCASE
IF filename EQ "" THEN RETURN
root_name = FSC_Base_Filename(filename, DIRECTORY=dirName)
outname = Filepath(ROOT_DIR=dirname, root_name)
; What kind of raster file.
CASE rasterType OF
; Normal raster.
0: BEGIN
void = TVRead(TYPE=fileType, FILENAME=outname, /NODIALOG)
END
; Raster via ImageMagick.
1: BEGIN
; Create a PostScript file first.
thisname = outname + '.ps'
PS_Start, $
EUROPEAN=self.ps_metric, $
SCALE_FACTOR=self.ps_scale_factor, $
CHARSIZE=self.ps_charsize, $
FONT=self.ps_font, $
TT_FONT=self.ps_tt_font
; Draw the graphics.
self -> ExecuteCommands
; Close the file and convert to proper file type.
CASE filetype OF
'BMP': PS_END, /BMP, DELETE_PS=self.ps_delete, $
ALLOW_TRANSPARENT=self.im_transparent, $
DENSITY=self.im_density, RESIZE=self.im_resize, $
IM_OPTIONS=self.im_options
'GIF': PS_END, /GIF, DELETE_PS=self.ps_delete, $
ALLOW_TRANSPARENT=self.im_transparent, $
DENSITY=self.im_density, RESIZE=self.im_resize, $
IM_OPTIONS=self.im_options
'JPEG': PS_END, /JPEG, DELETE_PS=self.ps_delete, $
ALLOW_TRANSPARENT=self.im_transparent, $
DENSITY=self.im_density, RESIZE=self.im_resize, $
IM_OPTIONS=self.im_options
'PNG': PS_END, /PNG, DELETE_PS=self.ps_delete, $
ALLOW_TRANSPARENT=self.im_transparent, $
DENSITY=self.im_density, RESIZE=self.im_resize, $
IM_OPTIONS=self.im_options
'TIFF': PS_END, /TIFF, DELETE_PS=self.ps_delete, $
ALLOW_TRANSPARENT=self.im_transparent, $
DENSITY=self.im_density, RESIZE=self.im_resize, $
IM_OPTIONS=self.im_options
ENDCASE
END
ENDCASE
; Set the window index number back.
IF WindowAvailable(curentWindow) THEN WSet, currentWindow ELSE WSet, -1
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method sets properties of the window object.
;-
PRO FSC_CmdWindow::SetProperty, $
BACKGROUND=background, $ ; The background color of the window.
DELAY=delay, $ ; The delay between command execution.
ERASEIT=eraseit, $ ; Set the erase flag for the window
PALETTE=palette, $ ; Change window color table vectors.
MULTI=multi, $ ; Change the !P.MULTI setting for the window.
XOMARGIN=xomargin, $ ; Change the !X.OMargin setting for the winow.
YOMARGIN=yomargin, $ ; Change the !Y.OMargin setting for the window.
UPDATE=update, $ ; Set if you want the commands to be updated after property change.
IM_TRANSPARENT=im_transparent, $ ; Sets the "alpha" keyword on ImageMagick convert command.
IM_DENSITY=im_density, $ ; Sets the density parameter on ImageMagick convert command.
IM_RESIZE=im_resize, $ ; Sets the resize parameter on ImageMagick convert command.
IM_OPTIONS=im_options, $ ; Sets extra ImageMagick options on the ImageMagick convert command.
PS_DELETE=ps_delete, $ ; Delete the PostScript file when making IM raster files.
PS_METRIC=ps_metric, $ ; Select metric measurements in PostScript output.
PS_ENCAPSULATED=ps_encapsulated, $ ; Select encapusulated PostScript output.
PS_FONT=ps_font, $ ; Select the font for PostScript output.
PS_CHARSIZE=ps_charsize, $ ; Select the character size for PostScript output.
PS_SCALE_FACTOR=ps_scale_factor, $ ; Select the scale factor for PostScript output.
PS_TT_FONT=ps_tt_font ; Select the true-type font to use for PostScript output.
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
IF N_Elements(background) NE 0 THEN BEGIN
IF Ptr_Valid(self.background) $
THEN *self.background = background $
ELSE self.background = Ptr_New(background)
ENDIF
IF N_Elements(palette) NE 0 THEN BEGIN
IF Size(palette, /N_DIMENSIONS) NE 2 THEN Message, 'Color palette is not a 3xN array.'
dims = Size(palette, /DIMENSIONS)
threeIndex = Where(dims EQ 3)
IF ((threeIndex)[0] LT 0) THEN Message, 'Color palette is not a 3xN array.'
IF threeIndex[0] EQ 0 THEN palette = Transpose(palette)
*self.r = palette[*,0]
*self.g = palette[*,1]
*self.b = palette[*,2]
ENDIF
IF N_Elements(delay) NE 0 THEN self.delay = delay
IF N_Elements(eraseit) NE 0 THEN self.eraseit = Keyword_Set(eraseit)
IF N_Elements(multi) NE 0 THEN BEGIN
IF (N_Elements(multi) EQ 1) && (multi EQ 0) THEN multi = IntArr(5)
FOR j=0,N_Elements(multi)-1 DO self.pmulti[j] = multi[j]
ENDIF
IF N_Elements(xomargin) NE 0 THEN self.xomargin = xomargin
IF N_Elements(yomargin) NE 0 THEN self.yomargin = yomargin
IF N_Elements(im_transparent) NE 0 THEN self.im_transparent = im_transparent
IF N_Elements(im_density) NE 0 THEN self.im_density = im_density
IF N_Elements(im_resize) NE 0 THEN self.im_resize = im_resize
IF N_Elements(im_options) NE 0 THEN self.im_options = im_options
IF N_Elements(ps_delete) NE 0 THEN self.ps_delete = ps_delete
IF N_Elements(ps_metric) NE 0 THEN self.ps_metric = ps_metric
IF N_Elements(ps_encapsulated) NE 0 THEN self.ps_encapsulated = ps_encapsulated
IF N_Elements(ps_charsize) NE 0 THEN self.ps_charsize = ps_charsize
IF N_Elements(ps_font) NE 0 THEN self.ps_font = ps_font
IF N_Elements(ps_scale_factor) NE 0 THEN self.ps_scale_factor = ps_scale_factor
IF N_Elements(ps_tt_font) NE 0 THEN self.ps_tt_font = ps_tt_font
; Update now?
IF Keyword_Set(update) THEN self -> ExecuteCommands
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_CmdWindow_Cleanup, tlb
Widget_Control, tlb, Get_UValue=self
Obj_Destroy, self
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; This method initializes the object that is at the heart of FSC_Window.
; It takes most of the same arguments as FSC_Window.
;-
FUNCTION FSC_CmdWindow::Init, $
command, $ ; The graphics "command" to execute.
p1, p2, p3, $ ; The three allowed positional parameters.
_Extra = extra, $ ; Any extra keywords. Usually the "command" keywords.
Group_Leader = group_leader, $ ; The group leader of the FSC_Window program.
AddCmd=addcmd, $ ; Set this keyword to add a command to the interface.
CmdDelay=cmdDelay, $ ; Set this keyword to a value to "wait" before executing the next command.
Method=method, $ ; If set, will use CALL_METHOD instead of CALL_PROCEDURE to execute command.
ReplaceCmd=replacecmd, $ ; Replace the current command and execute in the current window.
WEraseIt = Weraseit, $ ; Set this keyword to erase the display before executing the command.
WMulti = wmulti, $ ; Set this in the same way !P.Multi is used.
WOXMargin = woxmargin, $ ; Set the !X.OMargin. A two element array.
WOYMargin = woymargin, $ ; Set the !Y.OMargin. A two element array
WXSize = wxsize, $ ; The X size of the FSC_Window graphics window in pixels. By default: 400.
WYSize = wysize, $ ; The Y size of the FSC_Window graphics window in pixels. By default: 400.
WTitle = wtitle, $ ; The window title.
WXPos = wxpos, $ ; The X offset of the window on the display. The window is centered if not set.
WYPos = wypos, $ ; The Y offset of the window on the display. The window is centered if not set.
WBackground = wbackground ; The background color. Set to !P.Background by default.
Compile_Opt idl2
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN, 0
ENDIF
; Check keywords.
method = Keyword_Set(method)
; Get the global defaults.
FSC_Window_Get_Defaults, $
Background = d_background, $ ; The background color.
Delay = d_delay, $ ; The amount of delay between command execution.
EraseIt = d_eraseit, $ ; Set this keyword to erase the display before executing the commands.
Multi = d_multi, $ ; Set this in the same way !P.Multi is used.
XOMargin = d_xomargin, $ ; Set the !X.OMargin. A two element array.
YOMargin = d_yomargin, $ ; Set the !Y.OMargin. A two element array
XSize = d_xsize, $ ; The X size of the FSC_Window graphics window.
YSize = d_ysize, $ ; The Y size of the FSC_Window graphics window.
Title = d_title, $ ; The window title.
XPos = d_xpos, $ ; The X offset of the window on the display.
YPos = d_ypos, $ ; The Y offset of the window on the display.
Palette = d_palette, $ ; The color table palette to use for the window.
; ImageMagick Properties.
IM_Transparent = d_im_transparent, $ ; Sets the "alpha" keyword on ImageMagick convert command.
IM_Density = d_im_density, $ ; Sets the density parameter on ImageMagick convert command.
IM_Resize = d_im_resize, $ ; Sets the resize parameter on ImageMagick convert command.
IM_Options = d_im_options, $ ; Sets extra ImageMagick options on the ImageMagick convert command.
; PostScript properties.
PS_Delete = d_ps_delete, $ ; Delete PS file when making IM raster.
PS_Metric = d_ps_metric, $ ; Select metric measurements in PostScript output.
PS_Encapsulated = d_ps_encapsulated, $ ; Create Encapsulated PostScript output.
PS_FONT = d_ps_font, $ ; Select the font for PostScript output.
PS_CHARSIZE = d_ps_charsize, $ ; Select the character size for PostScript output.
PS_SCALE_FACTOR = d_ps_scale_factor, $ ; Select the scale factor for PostScript output.
PS_TT_FONT = d_ps_tt_font ; Select the true-type font to use for PostScript output.
; If method is set, the first positional parameter must be present,
; and it must be a valid object reference.
IF method THEN BEGIN
IF N_Elements(p1) EQ 0 THEN $
Message, 'The first positional parameter must be present to make a method call.'
IF ~Obj_Valid(p1) THEN $
Message, 'The first positional parameter must be a valid object reference when making method calls.'
ENDIF
IF N_Elements(wxsize) EQ 0 THEN xsize = d_xsize ELSE xsize = wxsize
IF N_Elements(wysize) EQ 0 THEN ysize = d_ysize ELSE ysize = wysize
IF N_Elements(wxpos) EQ 0 THEN xpos = d_xpos ELSE xpos = wxpos
IF N_Elements(wypos) EQ 0 THEN ypos = d_ypos ELSE ypos = wypos
IF N_Elements(wbackground) EQ 0 THEN BEGIN
wbackground = d_background
IF N_Elements(command) EQ 0 THEN weraseit = 1
IF (N_Elements(command) NE 0) && CoyoteGraphic(command) THEN weraseit = 1
ENDIF ELSE BEGIN
weraseit = 1
ENDELSE
IF N_Elements(weraseIt) EQ 0 THEN weraseIt = d_eraseit ELSE weraseIt = Keyword_Set(weraseIt)
; The commands will be placed in a linked list for execution.
self.cmds = Obj_New('LinkedList')
IF Obj_Valid(self.cmds) EQ 0 THEN Message, 'Failed to make the LinkedList for the commands.'
; Add a command, if you have one. Otherwise, just make the window.
IF (N_Elements(command) NE 0) THEN BEGIN
thisCommand = Obj_New('FSC_Window_Command', COMMAND=command, $
P1=p1, P2=p2, P3=p3, KEYWORDS=extra, TYPE=method)
IF Obj_Valid(thisCommand) THEN self.cmds -> Add, thisCommand ELSE Message, 'Failed to make command object.'
ENDIF
; If there is a palette, use it. Otherwise, use the current color table vectors.
IF Total(d_palette) NE 0 THEN BEGIN
IF Size(d_palette, /N_DIMENSIONS) NE 2 THEN Message, 'Color palette is not a 3xN array.'
dims = Size(d_palette, /DIMENSIONS)
threeIndex = Where(dims EQ 3)
IF ((threeIndex)[0] LT 0) THEN Message, 'Color palette is not a 3xN array.'
IF threeIndex[0] EQ 0 THEN d_palette = Transpose(d_palette)
self.r = Ptr_New(d_palette[*,0])
self.g = Ptr_New(d_palette[*,1])
self.b = Ptr_New(d_palette[*,2])
ENDIF ELSE BEGIN
TVLCT, rr, gg, bb, /Get
self.r = Ptr_New(rr)
self.g = Ptr_New(gg)
self.b = Ptr_New(bb)
ENDELSE
; Create the widgets for the program.
self.tlb = Widget_Base(/TLB_SIZE_EVENTS, MBar=menuID)
saveID = Widget_Button(menuID, Value='Save As...')
button = Widget_Button(saveID, Value='PostScript File', UVALUE='POSTSCRIPT')
raster = Widget_Button(saveID, Value='Raster Image File', /MENU)
button = Widget_Button(raster, Value='BMP', UVALUE='RASTER_BMP')
button = Widget_Button(raster, Value='GIF', UVALUE='RASTER_GIF')
button = Widget_Button(raster, Value='JPEG', UVALUE='RASTER_JPEG')
button = Widget_Button(raster, Value='PNG', UVALUE='RASTER_PNG')
button = Widget_Button(raster, Value='TIFF', UVALUE='RASTER_TIFF')
; If you can find ImageMagick on this machine, you can convert to better
; looking raster files.
IF HasImageMagick() EQ 1 THEN BEGIN
imraster = Widget_Button(saveID, Value='Raster Image File via ImageMagick', /MENU)
button = Widget_Button(imraster, Value='BMP', UVALUE='IMAGEMAGICK_BMP')
button = Widget_Button(imraster, Value='GIF', UVALUE='IMAGEMAGICK_GIF')
button = Widget_Button(imraster, Value='JPEG', UVALUE='IMAGEMAGICK_JPEG')
button = Widget_Button(imraster, Value='PNG', UVALUE='IMAGEMAGICK_PNG')
button = Widget_Button(imraster, Value='TIFF', UVALUE='IMAGEMAGICK_TIFF')
ENDIF
; Create draw widget.
retain = (StrUpCase(!Version.OS_Family) EQ 'UNIX') ? 2 : 1
self.drawID = Widget_Draw(self.tlb, XSIZE=xsize, YSize=ysize, RETAIN=retain)
; Do we need to center the widget?
IF (xpos EQ -1) AND (ypos EQ -1) THEN BEGIN
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF ~exists THEN BEGIN
xpos = 5
ypos = 5
ENDIF ELSE BEGIN
IF Obj_Valid(!FSC_WINDOW_LIST) THEN BEGIN
count = !FSC_WINDOW_LIST -> Get_Count()
xpos = 5 + (30*count)
ypos = 5 + (25*count)
ENDIF ELSE BEGIN
xpos = 5
ypos = 5
ENDELSE
ENDELSE
CenterTLB, self.tlb, xpos, ypos, /NOCENTER, /DEVICE
ENDIF ELSE BEGIN
CenterTLB, self.tlb, xpos, ypos, /NOCENTER, /DEVICE
ENDELSE
; Display the widget and get window index number.
currentWindow = !D.Window
Widget_Control, self.tlb, /Realize
Widget_Control, self.drawID, Get_Value=wid
self.wid = wid
IF N_Elements(wtitle) EQ 0 THEN BEGIN
wtitle = d_title
wtitle = wtitle + ' (' + StrTrim(wid,2) + ')'
ENDIF
Widget_Control, self.tlb, TLB_Set_Title=wtitle
; Load object properties.
self.background = Ptr_New(wbackground)
IF N_Elements(cmdDelay) NE 0 THEN self.delay = cmdDelay ELSE self.delay = d_delay
self.eraseIt = weraseIt
IF N_Elements(wmulti) NE 0 THEN BEGIN
FOR j=0,N_Elements(wmulti)-1 DO self.pmulti[j] = wmulti[j]
ENDIF ELSE self.pmulti = d_multi
IF N_Elements(wxomargin) NE 0 THEN self.xomargin = wxomargin ELSE self.xomargin = d_xomargin
IF N_Elements(wyomargin) NE 0 THEN self.yomargin = wyomargin ELSE self.yomargin = d_yomargin
self.im_transparent = d_im_transparent
self.im_density = d_im_density
self.im_options = d_im_options
self.im_resize = d_im_resize
self.ps_delete = d_ps_delete
self.ps_encapsulated = d_ps_encapsulated
self.ps_metric = d_ps_metric
self.ps_charsize = d_ps_charsize
self.ps_font = d_ps_font
self.ps_scale_factor = d_ps_scale_factor
self.ps_tt_font = d_ps_tt_font
; Execute the commands.
self -> ExecuteCommands
; Get it running.
WIDGET_CONTROL, /MANAGED, self.tlb
XManager, 'fsc_window', self.tlb, /No_Block, $
Event_Handler='FSC_CmdWindow_Dispatch_Events', $
Cleanup = 'FSC_CmdWindow_Cleanup', $
Group_Leader=group_leader
; Store the self reference in the UVALUE of the TLB.
Widget_Control, self.tlb, SET_UValue=self
; Each instance of FSC_Window will store evidence of its
; existance in a linked list.
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF ~exists THEN BEGIN
fsc_window_list = Obj_New("LinkedList")
DefSysV, '!FSC_WINDOW_LIST', fsc_window_list
fsc_window_list -> Add, {FSC_WINDOW_ID, self.tlb, wid, wtitle, self}
ENDIF ELSE BEGIN
IF Obj_Valid(!FSC_WINDOW_LIST) THEN BEGIN
!FSC_WINDOW_LIST -> Add, {FSC_WINDOW_ID, self.tlb, wid, wtitle, self}
ENDIF ELSE BEGIN
!FSC_WINDOW_LIST = Obj_New('LinkedList')
!FSC_WINDOW_LIST-> Add, {FSC_WINDOW_ID, self.tlb, wid, wtitle, self}
ENDELSE
ENDELSE
; Restore the current graphics window, if you can.
IF (currentWindow GE 0) && WindowAvailable(currentWindow) THEN BEGIN
WSet, currentWindow
ENDIF ELSE WSet, -1
RETURN, 1
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_CmdWindow::Cleanup
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
; Free any pointers.
Ptr_Free, self.background
Ptr_Free, self.r
Ptr_Free, self.g
Ptr_Free, self.b
; Destroy the command objects.
count = self.cmds -> Get_Count()
FOR j=0,count-1 DO Obj_Destroy, self.cmds -> Get_Item(j, /DEREFERENCE)
Obj_Destroy, self.cmds
; You have to remove yourself from the list of valid FSC_Windows.
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
index = Where(structs.windowObj[*] EQ self, count)
IF count GT 0 THEN theList -> Delete, index[0]
ENDIF
; If the list doesn't have any more FSC_Windows objects in it,
; delete the list so it doesn't waste memory.
IF theList -> Get_Count() EQ 0 THEN Obj_Destroy, theList
; If your widget ID is valid, destroy the widget program.
IF Widget_Info(self.tlb, /VALID_ID) THEN Widget_Control, self.tlb, /Destroy
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_CmdWindow__Define, class
class = { FSC_CMDWINDOW, $
tlb: 0L, $ ; The identifier of the top-level base widget.
cmds: Obj_New(), $ ; A linkedlist object containing the graphics commands.
wid: 0L, $ ; The window index number of the graphics window.
drawid: 0L, $ ; The identifier of the draw widget.
; FSC_Window parameters
background: Ptr_New(), $ ; The background color.
delay: 0.0, $ ; The command delay.
eraseit: 0B, $ ; Do we need to erase the display.
pmulti: LonArr(5), $ ; Identical to !P.Multi.
xomargin: FltArr(2), $ ; Identical to !X.OMargin
yomargin: FltArr(2), $ ; Identical to !Y.OMargin
r: Ptr_New(), $ ; The red color table vector.
g: Ptr_New(), $ ; The green color table vector.
b: Ptr_New(), $ ; The blue color table vector.
; PostScript options.
ps_delete: 0L, $ ; Delete the PS file when making IM image file.
ps_encapsulated: 0L, $ ; Encapsulated PostScript
ps_metric: 0L, $ ; Metric measurements in PostScript.
ps_charsize: 0.0, $ ; The character size to use for PostScript output.
ps_font: 0, $ ; The PostScript font to use.
ps_scale_factor: 0, $ ; The PostScript scale factor.
ps_tt_font: "", $ ; The name of a true-type font to use for PostScript output.
; ImageMagick output parameters.
im_transparent: 0B, $ ; Sets the "alpha" keyword on ImageMagick convert command.
im_density: 0L, $ ; Sets the density parameter on ImageMagick convert command.
im_resize: 0L, $ ; Sets the resize parameter on ImageMagick convert command.
im_options: "" $ ; Sets extra ImageMagick options on the ImageMagick convert command.
}
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_Window_Command::Draw, SUCCESS=success
Compile_Opt idl2
; Can't really catch CALL_PROCEDURE errors, so I'm not sure what this is doing here.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
;void = Error_Message()
success = 0
RETURN
ENDIF
; It seems it is not possible to catch errors generated by CALL_PROCEDURE,
; so I have to fake it out. I reset the !ERROR_STATE structure at the beginning
; and assume failure. After I get through the code, I check to see if the
; !ERROR_STATE.MSG field is still a null string. If it is, I assume we successfully
; executed the command and change the success flag.
success = 0
Message, /RESET
; What kind of command is this?
CASE self.type OF
; Command calls a procedure.
0: BEGIN
IF Ptr_Valid(self.keywords) THEN BEGIN
CASE self.nparams OF
0: Call_Procedure, self.command, _Extra=*self.keywords
1: Call_Procedure, self.command, *self.p1, _Extra=*self.keywords
2: Call_Procedure, self.command, *self.p1, *self.p2, _Extra=*self.keywords
3: Call_Procedure, self.command, *self.p1, *self.p2, *self.p3, _Extra=*self.keywords
ENDCASE
ENDIF ELSE BEGIN
CASE self.nparams OF
0: Call_Procedure, self.command
1: Call_Procedure, self.command, *self.p1
2: Call_Procedure, self.command, *self.p1, *self.p2
3: Call_Procedure, self.command, *self.p1, *self.p2, *self.p3
ENDCASE
ENDELSE
END
; Command calls a method.
1: BEGIN
IF Ptr_Valid(self.keywords) THEN BEGIN
CASE self.nparams OF
0: Call_Method, self.command, _Extra=*self.keywords
1: Call_Method, self.command, *self.p1, _Extra=*self.keywords
2: Call_Method, self.command, *self.p1, *self.p2, _Extra=*self.keywords
3: Call_Method, self.command, *self.p1, *self.p2, *self.p3, _Extra=*self.keywords
ENDCASE
ENDIF ELSE BEGIN
CASE self.nparams OF
0: Call_Method, self.command
1: Call_Method, self.command, *self.p1
2: Call_Method, self.command, *self.p1, *self.p2
3: Call_Method, self.command, *self.p1, *self.p2, *self.p3
ENDCASE
ENDELSE
END
ENDCASE
; If nothing has been put into the message field, we much have executed the command
; successfully.
IF !Error_State.MSG EQ "" THEN success = 1
; For some reason, CALL_PROCEDURE does not flush the graphics buffer on UNIX machines.
; We have to do it ourself to get the program to resize correctly on UNIX machines.
EMPTY
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_Window_Command::List, prefix
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN
ENDIF
cmdString = self.command
CASE self.nparams OF
0:
1: cmdString = cmdString + ', p1'
2: cmdString = cmdString + ', p1, p2'
3: cmdString = cmdString + ', p1, p2, p3'
ENDCASE
IF Ptr_Valid(self.keywords) THEN BEGIN
tags = Tag_Names(*self.keywords)
FOR j=0,N_Elements(tags)-1 DO BEGIN
cmdString = cmdString + ', ' + tags[j] + '=value'
ENDFOR
ENDIF
IF N_Elements(prefix) NE 0 THEN prefix = ' ' + prefix + ' ' ELSE prefix = ' '
Print, prefix + cmdString
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_Window_Command::Cleanup
Ptr_Free, self.p1
Ptr_Free, self.p2
Ptr_Free, self.p3
Ptr_Free, self.keywords
END ;----------------------------------------------------------------------------------------------------------------
FUNCTION FSC_Window_Command::INIT, $
COMMAND=command, $
P1=p1, P2=p2, P3=p3, $
KEYWORDS=keywords, $
TYPE=type
Compile_Opt idl2
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message()
RETURN, 0
ENDIF
self.command = command
IF N_Elements(p1) NE 0 THEN self.p1 = Ptr_New(p1)
IF N_Elements(p2) NE 0 THEN self.p2 = Ptr_New(p2)
IF N_Elements(p3) NE 0 THEN self.p3 = Ptr_New(p3)
IF N_Elements(keywords) NE 0 THEN self.keywords = Ptr_New(keywords)
self.type = type
self.nparams = (N_Elements(p1) NE 0) + (N_Elements(p2) NE 0) + (N_Elements(p3) NE 0)
RETURN, 1
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_Window_Command__Define
; The definition of the command object.
class = { FSC_Window_Command, $
command: "", $ ; The command to execute.
p1: Ptr_New(), $ ; The first parameter.
p2: Ptr_New(), $ ; The second parameter.
p3: Ptr_New(), $ ; The third parameter.
nparams: 0, $ ; The number of parameters.
keywords: Ptr_New(), $ ; The command keywords.
type: 0 $ ; =0 call_procedure =1 call_method
}
END ;----------------------------------------------------------------------------------------------------------------
PRO FSC_Window_ID__Define
struct = { FSC_WINDOW_ID, $
tlb: 0L, $
wid: 0L, $
title: "", $
windowObj: Obj_New() $
}
END ;----------------------------------------------------------------------------------------------------------------
;+
; :Description:
; Creates a resizeable graphics window for IDL traditional commands (Plot, Contour,
; Surface, etc. or for Coyote Graphics routines, FSC_Plot, FSC_Contour, FSC_Surf, etc.).
; In addition, the window contents can be saved as PostScript files or as raster image
; files. If ImageMagick is installed on your machine, the raster image files can be
; created in very high quality from PostScript files.
;
; :Categories:
; Graphics
;
; :Params:
; command: in, required, type=string
; The graphics procedure command to be executed. This parameter
; must be a string and the the command must be a procedure. Examples
; are 'Surface', 'Contour', 'Plot', 'FSC_Plot', FSC_Contour, etc.
; p1: in, optional, type=any
; The first positional parameter appropriate for the graphics command.
; p2: in, optional, type=any
; The second positional parameter appropriate for the graphics command.
; p3: in, optional, type=any
; The third positional parameter appropriate for the graphics command.
;
; :Keywords:
; addcmd: in, optional, type=boolean, default=0
; Set this keyword to add an additional graphics command to an FSC_Window.
; The command is added to the last created FSC_Window, unless the WinID
; keyword is used to select another FSC_Window. Adding a command causes
; all the commands in the window to be immediately executed. If this is
; not behavior you desire, use the LOADCMD keyword instead. If CMDINDEX
; is used to select a command index, the new command is added before
; the command currently occuping that index in the command list.
; cmddelay: in, optional, type=float
; If this keyword is set to a value other than zero, there will be a
; delay of this many seconds between command execution. This will permit
; "movies" of command sequences to be displayed.
; cmdindex: in, optional, type=integer
; This keyword is used to select which command in an FSC_Window to act on
; when the AllCmd, DeleteCmd, LoadCmd and ReplaceCmd keywords are used.
; See the descriptions of these keywords for details on what happens when
; CmdIndex is missing.
; deletecmd: in, optional, type=boolean, default=0
; Set this keyword to delete a graphics command from an FSC_Window.
; If CmdIndex is undefined the last command entered into the window is
; deleted. It is not possible to delete the last command in the window.
; Use WinID to identify the FSC_Window you are interested in. If WinID
; is undefined, the last FSC_Window created is used.
; executecmd: in, optional, type=boolean, default=0
; Set this keyword to immediate execute all the commands in an FSC_Window.
; Normally, this is used after commands have been loaded with LOADCMD.
; listcmd: in, optional, type=boolean, default=0
; If this keyword is set, the commands currently in the FSC_Window are
; listed. Use WinID to identify the FSC_Window you are interested in.
; If WinID is undefined, the last FSC_Window created is used.
; loadcmd: in, optional, type=boolean, default=0
; Set this keyword to add an additional graphics command to an FSC_Window.
; The command is added to the last created FSC_Window, unless the WinID
; keyword is used to select another FSC_Window. Loaded commands are not
; automatically executed. Set the EXECUTECMD keyword at the end of loading
; to execute the loaded commands. If CMDINDEX is used to select a command
; index, the new command is loaded before the command currently occuping
; that index in the command list.
; replacecmd: in, optional, type=boolean, default=0
; Set this keyword to replace a graphics command from an FSC_Window.
; If CmdIndex is undefined, *all* commands in the window are replaced. Use
; WinID to identify the FSC_Window you are interested in. If WinID is
; undefined, the last FSC_Window created is used for the replacement.
; group_leader: in, optional
; The identifier of a widget to serve as a group leader for this program.
; If the group leader is destroyed, this program is also destroyed. Used
; when calling this program from another widget program.
; method: in, optional, type=boolean, default=0
; Set this keyword if the command is an object method call rather than a
; procedure call. If this keyword is set, the first positional parameter, p1,
; must be present and must be a valid object reference.
; wbackground: in, optional, type=varies, default=!P.Background
; The background color of the window. Specifying a background color
; automatically sets the WErase keyword.
; werase: in, optional, type=boolean, default=0
; Set this keyword to cause the window to be erased before graphics commands
; are drawn. This may need to be set, for example, to display images.
; winid: in, optional, type=integer
; Use this keyword to select the window FSC_Window identifier (the number between
; the parentheses in the title bar of FSC_Window). The AddCmd, ReplaceCmd, ListCmd,
; and DeleteCmd keywords will all apply to the commands in the last FSC_Window
; created unless this keyword is used to select another FSC_Window to apply the
; commands to.
; wmulti: in, optional, type=intarr(5)
; Set this keyword in exactly the same way you would set the !P.Multi keyword.
; It will allow you to display multi-plots in the FSC_Window graphics window.
; wobject: out, optional, type=object
; FSC_Window creates a FSC_CmdWindow object. This object reference is returned
; if this keyword is present.
; wxpos: in, optional, type=integer, default=5
; The x offset in device coordinates of the FSC_Window from the upper-left corner of the display.
; wypos: in, optional, type=integer, default=5
; The y offset in device coordinates of the FSC_Window from the upper-left corner of the display.
; wxsize: in, optional, type=integer, default=640
; The x size in device coordinates of the graphics window.
; wysize: in, optional, type=integer, default=5
; The y size in device coordinates of the the graphics window.
; wtitle: in, opetional, type=string, default='Resizeable Graphics Window'
; The title of the graphics window. A window index number is appended to the
; title so multiple FSC_Window programs can be selected.
;
; :Examples:
; Test code::
; data = Loaddata(17)
; FSC_Window, 'FSC_Plot', data, COLOR='red'
; FSC_Window, 'FSC_Plot', data, PSYM=2, /Overplot, COLOR='dodger blue', /AddCmd
; FSC_WIndow, 'FSC_Plot', Loaddata(17), color='olive', linestyle = 2, /Overplot, /AddCmd
; FSC_Window, /ListCmd
; FSC_Window, 'FSC_Plot', data, COLOR='purple', /ReplaceCMD, CMDINDEX=0
;
; Additional examples can be found here:
;
; http://www.idlcoyote.com/graphics_tips/fsc_window.html
;
; :Notes:
; Notes on using the program::
;
; The program is designed to work with any IDL traditional graphics routine
; that is a procedure and includes no more than three positional parameters.
; Any number of keywords can be used to specify properties of the graphical
; output. Any number of graphics commands can be "added" the the FSC_Window.
; Simply use the ADDCMD keyword to add commands.
;
; If your program does not load its own color tables, the color tables in
; effect when FSC_Window is first called are used to display the graphics
; commands.
;
; To create PostScript output from within FSC_Window, your graphics program
; has to be written in such a way that it can work properly in the PostScript
; device. This means there are no Window commands, WSet commands, and the like
; that are not allowed in the PostScript device. Such commands are allowed in
; programs, of course, if they are "protected". Usually such protection looks
; like this:
;
; IF (!D.Flags AND 256) NE 0 THEN Window, ...
;
; FSC_Display is a good program for opening graphics "windows", because such
; PostScript protection is built into the program. In a PostScript device,
; FSC_Display produces a "window" with the same aspect ratio as the current
; dislay graphics window, which is an aid in producing PostScript output that
; looks like the same output in the display window.
;
; Much better looking raster files can be created from the FSC_Window contents,
; if the raster files are created by converting PostScript files to the raster
; file. If the ImageMagick "convert" command can be found on your machine, you
; will have the option to create raster files using this method. I *highly*
; recommend doing so, as fonts and other plot annotation will be of much higher
; quality using this method.
;
; FSC_Window has been designed to work with other Coyote Graphics routines: FSC_Plot,
; FSC_Contour, FSC_Surf, and so on, although I expect it to work with any IDL
; traditional graphics routine, if the routine is well written.
;
; :Author:
; FANNING SOFTWARE CONSULTING::
; David W. Fanning
; 1645 Sheely Drive
; Fort Collins, CO 80526 USA
; Phone: 970-221-0438
; E-mail: david@idlcoyote.com
; Coyote's Guide to IDL Programming: http://www.idlcoyote.com
;
; :History:
; Change History::
; Written, 17 January 2011. DWF.
; Fixed a problem with the example code, and added EMPTY to end of Draw method
; to force UNIX machines to empty the graphics buffer after CALL_PROCEDURE. 20 Jan 2011. DWF.
; Improved documentation and error handling. 19 Jan 2011. DWF.
; More improved error handling and messages. 26 Jan 2011. DWF.
; Made changes to accommodate the new FSC_WControl routine. 27 Jan 2011. DWF.
; Added WXOMARGIN and WYOMARGIN keywords. 28 Jan 2011. DWF.
;
; :Copyright:
; Copyright (c) 2011, Fanning Software Consulting, Inc.
;-
PRO FSC_Window, $
command, $ ; The graphics "command" to execute.
p1, p2, p3, $ ; The three allowed positional parameters.
_Extra = extra, $ ; Any extra keywords. Usually the "command" keywords.
Group_Leader = group_leader, $ ; The group leader of the FSC_Window program.
Method=method, $ ; If set, will use CALL_METHOD instead of CALL_PROCEDURE to execute command.
WBackground = wbackground, $ ; The background color. Set to !P.Background by default.
WErase = weraseit, $ ; Set this keyword to erase the display before executing the command.
WMulti = wmulti, $ ; Set this in the same way !P.Multi is used.
WOXMargin = woxmargin, $ ; Set the !X.OMargin. A two element array.
WOYMargin = woymargin, $ ; Set the !Y.OMargin. A two element array
WXSize = wxsize, $ ; The X size of the FSC_Window graphics window in pixels. By default: 640.
WYSize = wysize, $ ; The Y size of the FSC_Window graphics window in pixels. By default: 512.
WTitle = wtitle, $ ; The window title.
WXPos = wxpos, $ ; The X offset of the window on the display. The window is tiled if not set.
WYPos = wypos, $ ; The Y offset of the window on the display. The window is tiled if not set.
AddCmd=addcmd, $ ; Set this keyword to add a command to the interface and immediate execute commands.
CmdDelay=cmdDelay, $ ; Set this keyword to a value to "wait" before executing the next command.
CmdIndex=cmdIndex, $ ; Set this keyword to identify the index of the command to manipulate.
DeleteCmd=deletecmd, $ ; Set the keyword to delete a command.
ExecuteCmd=executecmd, $ ; Set this keyword to execute the commands in the window.
ListCmd=listCmd, $ ; Set this keyword to list the commands in the window.
LoadCmd=loadCmd, $ ; Set this keyword to load commands in the window, but not execute them.
ReplaceCmd=replacecmd, $ ; Set this keyword to replace a command in the window.
WinID=winid, $ ; Set this keyword to select an FSC_Window.
WObject=wobject ; The FSC_CMDWindow object. A return value.
Compile_Opt idl2
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /CANCEL
void = Error_Message(Traceback=0)
RETURN
ENDIF
; Did the user want to execute the commands in the window?
IF N_Elements(executeCmd) NE 0 THEN BEGIN
; Does the self object exist somewhere?
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF exists THEN BEGIN
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
IF Size(structs, /TNAME) EQ 'POINTER' THEN RETURN
IF N_Elements(winID) EQ 0 THEN BEGIN
winID = N_Elements(structs) - 1
ENDIF ELSE BEGIN
index = Where(structs.wid[*] EQ winID, count)
IF count GT 0 THEN winID = index[0] ELSE BEGIN
Message, 'Cannot find an FSC_Window with window index ' + StrTrim(winID, 2) + '.'
ENDELSE
ENDELSE
thisWindowStruct = structs[winID]
IF Obj_Valid(thisWindowStruct.windowObj) THEN BEGIN
thisWindowStruct.windowObj -> ExecuteCommands
ENDIF ELSE BEGIN
Message, 'The FSC_Window referred to does not exist.'
ENDELSE
RETURN
ENDIF ELSE Message, 'A valid FSC_Window does not exist to execute commands in.'
ENDIF ELSE Message, 'An FSC_Window object not exist to execute commands in.'
ENDIF
; Did the user want to list the commands in a FSC_Window?
IF N_Elements(listCmd) NE 0 THEN BEGIN
; Does the self object exist somewhere?
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF exists THEN BEGIN
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
IF Size(structs, /TNAME) EQ 'POINTER' THEN RETURN
IF N_Elements(winID) EQ 0 THEN BEGIN
winID = N_Elements(structs) - 1
ENDIF ELSE BEGIN
index = Where(structs.wid[*] EQ winID, count)
IF count GT 0 THEN winID = index[0] ELSE BEGIN
Message, 'Cannot find an FSC_Window with window index ' + StrTrim(winID, 2) + '.'
ENDELSE
ENDELSE
thisWindowStruct = structs[winID]
IF Obj_Valid(thisWindowStruct.windowObj) THEN BEGIN
thisWindowStruct.windowObj -> ListCommand
ENDIF ELSE BEGIN
Message, 'The FSC_Window referred to does not exist.'
ENDELSE
RETURN
ENDIF ELSE Message, 'A valid FSC_Window does not exist to list commands from.'
ENDIF ELSE Message, 'An FSC_Window object not exist to list commands from.'
ENDIF
; Did the user want to delete a command in the window?
IF N_Elements(deleteCmd) NE 0 THEN BEGIN
; Does the self object exist somewhere?
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF exists THEN BEGIN
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
IF Size(structs, /TNAME) EQ 'POINTER' THEN RETURN
IF N_Elements(winID) EQ 0 THEN BEGIN
winID = N_Elements(structs) - 1
ENDIF ELSE BEGIN
index = Where(structs.wid[*] EQ winID, count)
IF count GT 0 THEN winID = index[0] ELSE BEGIN
Message, 'Cannot find an FSC_Window with window index ' + StrTrim(winID, 2) + '.'
ENDELSE
ENDELSE
thisWindowStruct = structs[winID]
IF Obj_Valid(thisWindowStruct.windowObj) THEN BEGIN
; If the cmdIndex is undefined, the last entered command is deleted.
thisWindowStruct.windowObj -> DeleteCommand, cmdIndex
ENDIF ELSE BEGIN
Message, 'The FSC_Window referred to does not exist.'
ENDELSE
RETURN
ENDIF ELSE Message, 'The FSC_Window object is not a valid window object.'
ENDIF ELSE Message, 'An FSC_Window object not exist to add a command to.'
ENDIF
; Did the user want to replace a command or commands in the window?
IF Keyword_Set(replaceCmd) THEN BEGIN
; Must have a command to replace current command with.
IF N_Elements(command) EQ 0 THEN Message, 'No replacement command has been specified.'
; Does the self object exist somewhere?
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF exists THEN BEGIN
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
IF Size(structs, /TNAME) EQ 'POINTER' THEN RETURN
IF N_Elements(winID) EQ 0 THEN BEGIN
winID = N_Elements(structs) - 1
ENDIF ELSE BEGIN
index = Where(structs.wid[*] EQ winID, count)
IF count GT 0 THEN winID = index[0] ELSE BEGIN
Message, 'Cannot find an FSC_Window with window index ' + StrTrim(winID, 2) + '.'
ENDELSE
ENDELSE
thisWindowStruct = structs[winID]
IF Obj_Valid(thisWindowStruct.windowObj) THEN BEGIN
; Check command components.
IF Size(command, /TNAME) NE 'STRING' THEN $
Message, 'The first positional argument must be a command string.'
IF N_Params() GT 4 THEN $
Message, 'The maximum number of positional command parameters allowed is three.'
newCommand = Obj_New('FSC_Window_Command', COMMAND=command, $
P1=p1, P2=p2, P3=p3, KEYWORDS=extra, TYPE=Keyword_Set(method))
; If the cmdIndex is undefined, ALL current commands in the window are replaced.
thisWindowStruct.windowObj -> ReplaceCommand, newCommand, cmdIndex, MULTI=wmulti
thisWindowStruct.windowObj -> ExecuteCommands
ENDIF ELSE BEGIN
Message, 'The FSC_Window referred to does not exist.'
ENDELSE
RETURN
ENDIF ELSE Message, 'A valid FSC_Window does not exist to replace commands with.'
ENDIF ELSE Message, 'An FSC_Window does not exist to replace commands with.'
ENDIF
; Did the user want to load commands without executing them?
IF Keyword_Set(loadCmd) THEN BEGIN
; Does the self object exist somewhere?
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF exists THEN BEGIN
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
IF Size(structs, /TNAME) EQ 'POINTER' THEN RETURN
IF N_Elements(winID) EQ 0 THEN BEGIN
winID = N_Elements(structs) - 1
ENDIF ELSE BEGIN
index = Where(structs.wid[*] EQ winID, count)
IF count GT 0 THEN winID = index[0] ELSE BEGIN
Message, 'Cannot find an FSC_Window with window index ' + StrTrim(winID, 2) + '.'
ENDELSE
ENDELSE
thisWindowStruct = structs[winID]
IF Obj_Valid(thisWindowStruct.windowObj) THEN BEGIN
newCommand = Obj_New('FSC_Window_Command', COMMAND=command, $
P1=p1, P2=p2, P3=p3, KEYWORDS=extra, TYPE=Keyword_Set(method))
thisWindowStruct.windowObj -> AddCommand, newCommand, INDEX=cmdIndex
ENDIF ELSE BEGIN
Message, 'The FSC_Window referred to does not exist.'
ENDELSE
RETURN
ENDIF ELSE Message, 'A valid FSC_Window does not exist to add a command to.'
ENDIF ELSE Message, 'An FSC_Window does not exist to add a command to.'
ENDIF
; Did the user want to add a command to the window?
IF Keyword_Set(addCmd) THEN BEGIN
; Does the self object exist somewhere?
DefSysV, '!FSC_WINDOW_LIST', EXISTS=exists
IF exists THEN BEGIN
theList = !FSC_WINDOW_LIST
IF Obj_Valid(theList) THEN BEGIN
structs = theList -> Get_Item(/ALL, /DEREFERENCE)
IF Size(structs, /TNAME) EQ 'POINTER' THEN RETURN
IF N_Elements(winID) EQ 0 THEN BEGIN
winID = N_Elements(structs) - 1
ENDIF ELSE BEGIN
index = Where(structs.wid[*] EQ winID, count)
IF count GT 0 THEN winID = index[0] ELSE BEGIN
Message, 'Cannot find an FSC_Window with window index ' + StrTrim(winID, 2) + '.'
ENDELSE
ENDELSE
thisWindowStruct = structs[winID]
IF Obj_Valid(thisWindowStruct.windowObj) THEN BEGIN
newCommand = Obj_New('FSC_Window_Command', COMMAND=command, $
P1=p1, P2=p2, P3=p3, KEYWORDS=extra, TYPE=Keyword_Set(method))
thisWindowStruct.windowObj -> AddCommand, newCommand, INDEX=cmdIndex
thisWindowStruct.windowObj -> ExecuteCommands
ENDIF ELSE BEGIN
Message, 'The FSC_Window referred to does not exist.'
ENDELSE
RETURN
ENDIF ELSE Message, 'A valid FSC_Window does not exist to add a command to.'
ENDIF ELSE Message, 'An FSC_Window does not exist to add a command to.'
ENDIF
; Otherwise, make the command object.
wobject = Obj_New('FSC_CmdWindow', $
command, $ ; The graphics "command" to execute.
p1, p2, p3, $ ; The three allowed positional parameters.
_Extra = extra, $ ; Any extra keywords. Usually the "command" keywords.
CmdDelay = cmdDelay, $ ; The amount of time to "wait" between commands.
Group_Leader = group_leader, $ ; The group leader of the FSC_Window program.
Method=method, $ ; If set, will use CALL_METHOD instead of CALL_PROCEDURE to execute command.
WBackground = wbackground, $ ; The background color. Not used unless set.
WMulti = wmulti, $ ; Set this in the same way !P.Multi is used.
WErase = weraseit, $ ; Set this keyword to erase the display before executing the command.
WXSize = wxsize, $ ; The X size of the FSC_Window graphics window in pixels. By default: 400.
WYSize = wysize, $ ; The Y size of the FSC_Window graphics window in pixels. By default: 400.
WTitle = wtitle, $ ; The window title.
WXPos = wxpos, $ ; The X offset of the window on the display. The window is centered if not set.
WYPos = wypos ) ; The Y offset of the window on the display. The window is centered if not set.
END