source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/VSANS/V_Test_RAW_Panel.ipf @ 1037

Last change on this file since 1037 was 1035, checked in by srkline, 5 years ago

changes to streamline the data plotting of 1D data, in preparation for different modes of combining detector panels. Also will allow better integration with protocols to combine 1D data, which can now be part of the protocol.

Other changes, but I can't remember whtat they were...

File size: 36.8 KB
Line 
1#pragma rtGlobals=3             // Use modern global access method and strict wave access.
2#pragma version=1.0
3#pragma IgorVersion=6.1
4
5//
6// this will become the equivalent of "RawWindowHook"
7//
8// Procedures to:
9// display the detector data
10// visualization tools
11// mouse interaction
12// status information necessary to understand the data
13// buttons to more functionality to process data
14
15
16// TODO
17//
18// -- have the status automatically fill in when a new file is loaded, rather than needing a click of the "status" button
19// -- need a place somewhere to show the currently displayed folder
20// -- checkboxes for "active" corrections?
21// -- display of Q, counts, QxQy, X and Y
22// -- do I need a color bar? or is this not used at all? I like it to be there, or the colors are a waste of information
23//              (then... where do I put the color bar?)
24// -- define the "hook" function, and attach it to the panel (or the main detector subwindow?)
25//
26
27
28//
29// call this after loading data to either draw the data display panel or to update the contents
30//
31// TODO
32// -- make sure that the "type" input is correctly used for the updating of the data, values, etc.
33// -- add a procedure to define the global variables for pos, counts, QxQy, etc.
34//
35Function V_UpdateDisplayInformation(type)
36        String type
37       
38        DoWindow/F VSANS_Data
39//      Print V_flag
40        if(V_flag==0)
41       
42                VSANSDataPanelGlobals()
43               
44                Execute "VSANS_DataPanel()"             //draws the panel
45
46        endif
47       
48        // TODO: update the information here  - in either case
49        // what isn't automatically picked up? What is "stale" on the display?
50        String/G root:Packages:NIST:VSANS:Globals:gCurDispType = type
51       
52        // fake a click on all three tabs - to populate the data
53        V_FakeTabClick(2)
54        V_FakeTabClick(1)
55        V_FakeTabClick(0)
56
57        V_LogLinDisplayPref()           // resets the display depending on the preference state
58       
59        // either clear the status, or fake a click
60//      root:Packages:NIST:VSANS:Globals:gStatusText = "status info box"
61
62        V_FakeStatusButtonClick()
63
64        V_FakeRestorePanelsButtonClick()                //so the panels display correctly
65
66       
67//      DoWindow/T VSANS_Data,type + " VSANS_Data"
68
69        String newTitle = "WORK_"+type
70        DoWindow/F VSANS_Data
71        DoWindow/T VSANS_Data, newTitle
72        KillStrings/Z newTitle
73       
74end
75
76Function V_LogLinDisplayPref()
77
78        // get the state of the log/lin button, and make sure preferences are obeyed
79        // log/lin current state is in the S_UserData string (0=linear, 1=log)
80        ControlInfo/W=VSANS_Data button_log
81        Variable curState
82        curState = str2num(S_UserData)
83
84        NVAR gLogScalingAsDefault = root:Packages:NIST:VSANS:Globals:gLogScalingAsDefault
85        if(curState != gLogScalingAsDefault)
86                STRUCT WMButtonAction ba
87                ba.eventCode = 2                //fake mouse click
88                V_LogLinButtonProc(ba)
89        endif
90       
91        return(0)
92end
93
94
95//
96// creates/initializes the globals for display of the data panel
97//
98Function VSANSDataPanelGlobals()
99
100        SetDataFolder root:Packages:NIST:VSANS:Globals
101       
102        Variable/G gXPos=0
103        Variable/G gYPos=0
104        Variable/G gQX=0
105        Variable/G gQY=0
106        Variable/G gQQ=0
107        Variable/G gNCounts=0
108        String/G gCurDispFile = "default string"
109        String/G gCurTitle = ""
110        String/G gCurDispType = ""
111        String/G gStatusText = "status"
112        String/G gLastLoadedFile=""
113       
114        SetDataFolder root:
115End
116
117
118// TODO
119//
120// -- now that the sliders work, label them and move them to a better location
121// -- logical location for all of the buttons
122// -- add raw data load button, load/draw mask button
123// x- fill in the proper window title in the DoWindow/T command
124// -- add help text for all of the controls
125// -- tab order? can I set this?
126//
127Window VSANS_DataPanel() : Panel
128        PauseUpdate; Silent 1           // building window...
129        NewPanel /W=(37,45,1038,719) /N=VSANS_Data
130//      ShowTools/A
131        ModifyPanel cbRGB=(65535,60076,49151)
132
133        String curFolder = root:Packages:NIST:VSANS:Globals:gCurDispType
134        DoWindow/T VSANS_Data,curFolder + " VSANS_Data"
135        SetWindow VSANS_Data,hook(dataHook)=VSANSDataHook,hookevents=2
136       
137        SetDrawLayer UserBack
138        SetDrawEnv linethick= 2,dash= 1,fillpat= 0
139        DrawRect 200,70,310,160
140        SetDrawEnv linethick= 2,dash= 1,fillpat= 0
141        DrawRect 320,70,430,160
142        SetDrawEnv linethick= 2,dash= 1,fillpat= 0
143        DrawRect 440,70,550,160
144       
145        SetDrawEnv fsize= 18
146        DrawText 230,115,"Front"
147        SetDrawEnv fsize= 18
148        DrawText 348,115,"Middle"
149        SetDrawEnv fsize= 18
150        DrawText 476,115,"Back"
151       
152        ToolsGrid visible=1
153
154
155        TabControl tab0,pos={13,41},size={572,617},proc=V_DataTabProc,tabLabel(0)="Front"
156        TabControl tab0,tabLabel(1)="Middle",tabLabel(2)="Back",value= 2,focusRing=0
157
158// on the side 
159        Button button_status,pos={607,146},size={70,20},proc=V_StatusButtonProc,title="Status"
160        Button button_IvsQ,pos={689,113},size={70,20},proc=V_IvsQPanelButtonProc,title="I vs. Q"
161        Button button_file_m,pos={619,55},size={50,20},proc=V_File_minus_ButtonProc,title="File <"
162        Button button_file_p,pos={679,55},size={50,20},proc=V_File_plus_ButtonProc,title="File >"
163        Button button_log,pos={689,146},size={70,20},proc=V_LogLinButtonProc,title="isLin",userData="0"
164        Button button_tab_p,pos={648,81},size={50,20},proc=V_Tab_p_ButtonProc,title="Tab >"
165        Button button_isolate,pos={606,114},size={70,20},proc=V_IsolateButtonProc,title="Isolate"
166        Button button_toWork,pos={770,113},size={70,20},proc=V_ToWorkFileButtonProc,title="to WORK"
167
168        TitleBox title_file,pos={606,178},size={76,20},variable= root:Packages:NIST:VSANS:Globals:gLastLoadedFile
169        TitleBox title_dataPresent,pos={606,210},size={76,20},variable= root:Packages:NIST:VSANS:Globals:gCurDispFile
170        TitleBox title_status,pos={606,240},size={200,200},variable= root:Packages:NIST:VSANS:Globals:gStatusText
171       
172        Button button_tagFile,pos={603,412},size={70,20},proc=V_TagFileButtonProc,title="Tag File"
173        Button button_tagFile,disable=2
174        Button button_saveIQ,pos={720,412},size={70,20},proc=V_SaveIQ_ButtonProc,title="Save I(Q)"
175        Button button_BeamCtr,pos={603,450},size={70,20},proc=V_BeamCtrButtonProc,title="Beam Ctr"
176        Button button_SpreadPanels,pos={603,488},size={100,20},proc=V_SpreadPanelButtonProc,title="Spread Panels"
177        Button button_RestorePanels,pos={603,526},size={100,20},proc=V_RestorePanelButtonProc,title="Restore Panels"
178
179
180// on the tabs, always visible
181        TitleBox title_xy,pos={24,71},size={76,20},variable= root:Packages:NIST:VSANS:Globals:gLastLoadedFile
182        Slider slider_hi,pos={558,224},size={16,80},proc=V_HiMapSliderProc
183        Slider slider_hi,limits={0,1,0},value= 1,ticks= 0
184        Slider slider_lo,pos={558,315},size={16,80},proc=V_LowMapSliderProc
185        Slider slider_lo,limits={0,1,0},value= 0,ticks= 0
186
187        SetVariable xpos,pos={22,97},size={50,17},title="X "
188        SetVariable xpos,limits={-Inf,Inf,0},value= root:Packages:NIST:VSANS:Globals:gXPos
189        SetVariable xpos,help={"x-position on the detector"},frame=0,noedit=1
190        SetVariable ypos,pos={22,121},size={50,17},title="Y "
191        SetVariable ypos,limits={-Inf,Inf,0},value= root:Packages:NIST:VSANS:Globals:gYPos
192        SetVariable ypos,help={"y-position on the detector"},frame=0,noedit=1
193        SetVariable counts,pos={22,151},size={150,17},title="Counts "
194        SetVariable counts,limits={-Inf,Inf,0},value= root:Packages:NIST:VSANS:Globals:gNCounts
195        SetVariable counts,help={"Neutron counts"},frame=0,noedit=1
196        SetVariable qxval,pos={83,94},size={85,17},title="qX"
197        SetVariable qxval,help={"q value in the x-direction on the detector"},frame=0,noedit=1
198        SetVariable qxval,format="%+7.5f",limits={-Inf,Inf,0},value= root:Packages:NIST:VSANS:Globals:gQX
199        SetVariable qyval,pos={83,113},size={85,17},title="qY"
200        SetVariable qyval,help={"q value in the y-direction on the detector"},frame=0,noedit=1
201        SetVariable qyval,format="%+7.5f",limits={-Inf,Inf,0},value= root:Packages:NIST:VSANS:Globals:gQY
202        SetVariable q_pos,pos={83,132},size={85,17},title="q "
203        SetVariable q_pos,help={"q-value on the detector at (x,y)"},format="%+7.5f"
204        SetVariable q_pos,limits={-Inf,Inf,0},value= root:Packages:NIST:VSANS:Globals:gQQ,frame=0,noedit=1
205       
206        Make/O/D tmp_asdf
207        // for back panels (in pixels?)
208//      Display/W=(50,185,545,620)/HOST=# tmp_asdf
209        Display/W=(50,185,517,620)/HOST=# tmp_asdf
210        RenameWindow #,det_panelsB
211        ModifyGraph mode=2              // mode = 2 = dots
212        ModifyGraph marker=19
213        ModifyGraph rgb=(0,0,0)
214        ModifyGraph tick=2,mirror=1
215        Label left "pixels"
216        Label bottom "pixels"   
217        SetActiveSubwindow ##
218       
219        // for middle panels (in pixels?)       
220        Display/W=(50,185,517,620)/HOST=# tmp_asdf
221        RenameWindow #,det_panelsM
222        ModifyGraph mode=2              // mode = 2 = dots
223        ModifyGraph marker=19
224        ModifyGraph rgb=(0,0,0)
225        ModifyGraph tick=2,mirror=1
226        Label left "pixels"
227        Label bottom "pixels"   
228        SetActiveSubwindow ##
229       
230        // for front panels (in pixels?)       
231        Display/W=(50,185,517,620)/HOST=# tmp_asdf
232        RenameWindow #,det_panelsF
233        ModifyGraph mode=2              // mode = 2 = dots
234        ModifyGraph marker=19
235        ModifyGraph rgb=(0,0,0)
236        ModifyGraph tick=2,mirror=1
237        Label left "pixels"
238        Label bottom "pixels"   
239        SetActiveSubwindow ##
240       
241EndMacro
242
243//
244// event code 4: mouse moved
245// event code 11: keyboard events
246//
247// mouse moved is the only event that I really care about for the data display.
248//
249// TODO:
250// -- figure out how to respond only to events in the main window
251// -- figure out which is the correct image to respond "from"
252// -- More complete documentation of how the hook is identifying what graph is "under" the mouse
253//    AND what assumptions are behind this identification
254//
255//
256Function VSANSDataHook(s)
257        STRUCT WMWinHookStruct &s
258
259        Variable hookResult = 0
260
261        switch(s.eventCode)
262                case 0:                         // Activate
263                        // Handle activate
264//                      Print "Activate"
265                        break
266
267                case 1:                         // Deactivate
268                        // Handle deactivate
269                        break
270                       
271                case 3:         //mouse down
272//                      Print "mouse down"
273//
274// TODO (Way in the future -- I could make the small graphs into "buttons" by responding to a "mouse up" (not down)
275//    that hits in one of the small graph areas, and treat that as a click on that tab
276// -- instead of this, I can try to get the focus rectangle to work more easily to move with the TAB,
277//    if I can intercept the keystroke (event 11), see below.
278//
279                        break
280                       
281                case 4:         // mouse moved
282                        NVAR xloc = root:Packages:NIST:VSANS:Globals:gXPos
283                        NVAR yloc = root:Packages:NIST:VSANS:Globals:gYPos
284                        NVAR gQX = root:Packages:NIST:VSANS:Globals:gQX
285                        NVAR gQY = root:Packages:NIST:VSANS:Globals:gQY
286                        NVAR gQQ = root:Packages:NIST:VSANS:Globals:gQQ
287                        NVAR gNCounts = root:Packages:NIST:VSANS:Globals:gNCounts
288                        SVAR gCurDispFile = root:Packages:NIST:VSANS:Globals:gCurDispFile
289                        SVAR gCurDispType = root:Packages:NIST:VSANS:Globals:gCurDispType               //the current folder
290                        Variable xaxval,yaxval,tab
291                       
292                        // is the mouse location within the "main" display window?
293                        // if so, do something, if not, do nothing?
294                        // right now, the "main" display is at (50,185,545,620). its name depends on the active tab
295                       
296//                              xloc = s.mouseLoc.h
297//                              yloc = s.mouseLoc.v
298
299//                      if out of bounds, exit now
300//              TODO - currently the values are hard-wired. eliminate this later if the size of the graph changes
301                        if(s.mouseLoc.h < 50 || s.mouseLoc.h > 545 || s.mouseLoc.v < 185 || s.mouseLoc.v > 620)
302                                break
303                        endif   
304                       
305//                      if(in bounds)
306//                              get the point location
307//                              update the globals --
308//                              but which data instance am I pointing to?
309//                              deduce the carriage and panel, and calculate Q
310//                      endif
311
312                        GetWindow $s.winName activeSW
313                        String activeSubwindow = S_value                // returns something like: "VSANS_Data#det_panelsF"
314                               
315                        xaxval= AxisValFromPixel("","bottom",s.mouseLoc.h)
316                        yaxval= AxisValFromPixel("","left",s.mouseLoc.v)
317                        xloc = round(xaxval)
318                        yloc = round(yaxval)
319                       
320                        // which tab is selected? -this is the main graph panel (subwindow may not be the active one!)
321                        ControlInfo/W=VSANS_Data tab0
322                        tab = V_Value
323                        if(tab == 0)
324                                activeSubwindow = "VSANS_Data#det_panelsF"
325                        elseif (tab == 1)
326                                activeSubwindow = "VSANS_Data#det_panelsM"
327                        else
328                                activeSubwindow = "VSANS_Data#det_panelsB"
329                        endif
330                       
331                       
332                        // which images are here?
333                        String detStr="",imStr,carriageStr
334                        String currentImageRef
335                        String imageList = ImageNameList(activeSubwindow,";")
336                        Variable ii,nIm,testX,testY,xctr,yctr,sdd,lam,pixSizeX,pixSizeY
337                        nIm = ItemsInList(imageList,";")
338                        gCurDispFile = imageList
339                        if(nIm==0)
340                                break           //problem, get out
341                        endif
342
343                        // images were added in the order TBLR, so look back through in the order RLBT, checking each to see if
344                        // the xy value is found on that (scaled) array
345                                               
346                        // loop backwards through the list of panels (may only be one if on the back)
347                        for(ii=nIm-1;ii>=0;ii-=1)
348                                Wave w = ImageNameToWaveRef(activeSubwindow,StringFromList(ii, imageList,";"))
349                               
350                                // which, if any image is the mouse xy location on?
351                                // use a multidemensional equivalent to x2pnt: (ScaledDimPos - DimOffset(waveName, dim))/DimDelta(waveName,dim)
352
353                               
354                                testX = ScaleToIndex(w,xloc,0)
355                                testY = ScaleToIndex(w,yloc,1)
356                               
357                                if( (testX >= 0 && testX < DimSize(w,0)) && (testY >= 0 && testY < DimSize(w,1)) )
358                                        // we're in-bounds on this wave
359                                       
360                                        // count value to the global
361                                        gNCounts = w[testX][testY]
362                                       
363                                        // deduce the detector panel
364                                        currentImageRef = StringFromList(ii, imageList,";")     //the image instance ##
365                                        // string is "data", or "data#2" etc. - so this returns "", "1", "2", or "3"
366                                        imStr = StringFromList(1, currentImageRef,"#")         
367                                        carriageStr = activeSubWindow[strlen(activeSubWindow)-1]
368                                       
369                                        if(cmpstr(carriageStr,"B")==0)
370                                                detStr = carriageStr
371                                        else
372                                                if(strlen(imStr)==0)
373                                                        imStr = "9"                     // a dummy value so I can replace it later
374                                                endif
375                                                detStr = carriageStr+imStr              // "F2" or something similar
376                                                detStr = ReplaceString("9", detStr, "T")        // ASSUMPTION :::: instances 0123 correspond to TBLR
377                                                detStr = ReplaceString("1", detStr, "B")        // ASSUMPTION :::: this is the order that the panels
378                                                detStr = ReplaceString("2", detStr, "L")        // ASSUMPTION :::: are ALWAYS added to the graph
379                                                detStr = ReplaceString("3", detStr, "R")        // ASSUMPTION ::::
380                                        endif
381                                        gCurDispFile = detStr
382
383                                        // now figure out q
384                                        // calculate the q-values, will be different depending on which panel is up (pixel size, geometry, etc.)
385                                        // TODO: !!!! get rid of the hard-wired values
386                                        // TODO: be sure that the units from HDF are what I expect
387                                        // TODO: beam center XY are pixels in the file, expected in the function, but are better suited for mm or cm
388                                        // TODO: units of xy pixel size are likely wrong
389//                                      xctr = V_getDet_beam_center_x(gCurDispType,detStr)              //written in pixels
390//                                      yctr = V_getDet_beam_center_y(gCurDispType,detStr)
391                                        xctr = V_getDet_beam_center_x_mm(gCurDispType,detStr)           //written in mm
392                                        yctr = V_getDet_beam_center_y_mm(gCurDispType,detStr)   
393                                       
394                                        sdd = V_getDet_ActualDistance(gCurDispType,detStr)      / 100   //written in cm, pass in meters
395                                        lam = V_getWavelength(gCurDispType)             //A
396//                                      pixSizeX = V_getDet_x_pixel_size(gCurDispType,detStr)           // written mm? need mm
397//                                      pixSizeY = V_getDet_y_pixel_size(gCurDispType,detStr)           // written mm? need mm
398//
399// TODO: these q-values ignore the non-linear corrections!!!
400// -- What can I do about this?
401                                        String destPath = "root:Packages:NIST:VSANS:"+gCurDispType
402                                        Wave data_realDistX = $(destPath + ":entry:instrument:detector_"+detStr+":data_realDistX")
403                                        Wave data_realDistY = $(destPath + ":entry:instrument:detector_"+detStr+":data_realDistY")     
404                                       
405// TODO: figure out what coordinates I need to pass -- xloc, yloc, textX, testY, (+1 on any?)                           
406                                        //gQQ = VC_CalcQval(testX,testY,xctr,yctr,sdd,lam,pixSizeX,pixSizeY)
407                                        //gQX = VC_CalcQX(testX,testY,xctr,yctr,sdd,lam,pixSizeX,pixSizeY)
408                                        //gQY = VC_CalcQY(testX,testY,xctr,yctr,sdd,lam,pixSizeX,pixSizeY)
409                                        gQQ = V_CalcQval(testX,testY,xctr,yctr,sdd,lam,data_realDistX,data_realDistY)
410                                        gQX = V_CalcQX(testX,testY,xctr,yctr,sdd,lam,data_realDistX,data_realDistY)
411                                        gQY = V_CalcQY(testX,testY,xctr,yctr,sdd,lam,data_realDistX,data_realDistY)
412
413                                        ii = -1         //look no further, set ii to bad value to exit the for loop
414                                       
415                                        // TODO
416                                        // -- remove this - it sets the globals to display to the pixel values, unscaled
417//                                      xloc = testX
418//                                      yloc = testY
419                                       
420                                endif   //end if(mouse is over a detector panel)
421                        endfor          // end loop over list of displayed images
422               
423                        break
424                       
425                        case 11: // keyboard event
426                                // TODO -- figure out why I'm not getting the TAB keystroke
427                                //  -- I want to be able to use the tab to change the focus only between File <.> and Tab > buttons, not everything
428                                // see the help file section "Keyboard Events" for an example and "WMWinHookStruct"
429                               
430                                //Print "key code = ",s.specialKeyCode
431                                //hookresult = 1                //if non-zero, we handled it and Igor will ignore it
432                                break
433                // And so on . . .
434        endswitch
435
436        return hookResult               // 0 if nothing done, else 1
437End
438
439
440// ********
441//
442// this procedure does most of the work for drawing the panels, setting the proper log/lin
443// scaling, the color scale, and the location based on the active tab
444//
445//lots to to here:
446//
447// - 1 - display the appropriate controls for each tab, and hide the others
448// - 2 - display the correct detector data for each tab, and remove the others from the graph
449// -----?? can I draw 3 graphs, and just put the right one on top?? move the other two to the side?
450//
451//
452// TODO
453//  -- add all of the controls of the VCALC panel (log scaling, adjusting the axes, etc.)
454//  x- get the panel to be correctly populated first, rather than needing to click everywhere to fill in
455//  x- remove the dependency on VCALC being initialized first, and using dummy waves from there...
456//
457//
458Function V_DataTabProc(tca) : TabControl
459        STRUCT WMTabControlAction &tca
460
461        switch( tca.eventCode )
462                case 2: // mouse up
463                        Variable tab = tca.tab
464               
465//                      SetDataFolder root:Packages:NIST:VSANS:VCALC
466                        SetDataFolder root:
467                        RemoveFromGraph/Z /W=VSANS_Data#det_panelsB tmp_asdf
468                        RemoveFromGraph/Z /W=VSANS_Data#det_panelsM tmp_asdf
469                        RemoveFromGraph/Z /W=VSANS_Data#det_panelsF tmp_asdf
470                        SetDataFolder root:
471                       
472                        SVAR dataType = root:Packages:NIST:VSANS:Globals:gCurDispType
473                       
474// make sure log scaling is correct
475                        NVAR state = root:Packages:NIST:VSANS:Globals:gIsLogScale
476                        if(State == 0)
477                                // lookup wave
478                                Wave LookupWave = root:Packages:NIST:VSANS:Globals:linearLookupWave
479                        else
480                                // lookup wave - the linear version
481                                Wave LookupWave = root:Packages:NIST:VSANS:Globals:logLookupWave
482                        endif
483                                               
484                       
485                        //************
486                        // -- can I use "ReplaceWave/W=VSANS_Data#det_panelsB allinCDF" to do this?
487                        // -- only works for "B", since for M and F panels, all 4 data sets are named "data"
488                        // in their respective folders...
489                       
490                       
491                        // get the slider values for the color mapping
492                        Variable lo,hi,lo_B,hi_B
493                        Variable lo_MT,lo_MB,lo_MR,lo_ML
494                        Variable lo_FT,lo_FB,lo_FR,lo_FL
495                        Variable hi_MT,hi_MB,hi_MR,hi_ML
496                        Variable hi_FT,hi_FB,hi_FR,hi_FL
497                        ControlInfo slider_lo
498                        lo = V_Value
499                        ControlInfo slider_hi
500                        hi = V_Value
501                       
502                       
503                        String tmpStr
504                        Variable ii
505                        if(tab==2)
506                                tmpStr = ImageNameList("VSANS_Data#det_panelsB",";")
507                                // for some odd reason, it appears that I need to work from the back of the list
508                                // since the traces get "renumbered" as I take them off !! A do loop may be a better choice
509                                if(ItemsInList(tmpStr) > 0)
510                                        do
511                                                RemoveImage /W=VSANS_Data#det_panelsB $(StringFromList(0,tmpStr,";"))           //get 1st item
512                                                tmpStr = ImageNameList("VSANS_Data#det_panelsB",";")                                                            //refresh list
513                                        while(ItemsInList(tmpStr) > 0)
514                                endif
515                               
516                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_B")
517                                Wave det_B=data
518                               
519                                CheckDisplayed /W=VSANS_Data#det_panelsB det_B 
520                                if(V_flag == 0)         // 0 == data is not displayed, so append it
521                                        AppendImage/W=VSANS_Data#det_panelsB det_B
522                                        lo_B = lo*(WaveMax(det_B) - WaveMin(det_B)) + WaveMin(det_B)
523                                        hi_B = hi*(WaveMax(det_B) - WaveMin(det_B)) + WaveMin(det_B)
524                                        ModifyImage/W=VSANS_Data#det_panelsB ''#0 ctab= {lo_B,hi_B,ColdWarm,0}          // don't autoscale {*,*,ColdWarm,0}
525                                endif
526                                MoveSubWindow/W=VSANS_Data#det_panelsB fnum=(50,185,517,620)
527                                MoveSubWindow/W=VSANS_Data#det_panelsM fnum=(320,70,430,160)
528                                MoveSubWindow/W=VSANS_Data#det_panelsF fnum=(200,70,310,160)
529
530                                ModifyImage/W=VSANS_Data#det_panelsB ''#0 ctabAutoscale=0,lookup= LookupWave
531                               
532                                // make the plot square
533                                ModifyGraph/W=VSANS_Data#det_panelsB width={Aspect,1}
534                               
535                                SetActiveSubWindow VSANS_Data#det_panelsB
536                                SetDataFolder root:
537                        endif
538       
539                        if(tab==1)
540                                tmpStr = ImageNameList("VSANS_Data#det_panelsM",";")
541                                // for some odd reason, it appears that I need to work from the back of the list
542                                // since the traces get "renumbered" as I take them off !! A do loop may be a better choice
543                                if(ItemsInList(tmpStr) > 0)
544                                        do
545                                                RemoveImage /W=VSANS_Data#det_panelsM $(StringFromList(0,tmpStr,";"))           //get 1st item
546                                                tmpStr = ImageNameList("VSANS_Data#det_panelsM",";")                                                            //refresh list
547                                        while(ItemsInList(tmpStr) > 0)
548                                endif
549
550                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_ML")
551                                Wave det_ML=data                               
552                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_MR")
553                                Wave det_MR=data
554                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_MT")
555                                Wave det_MT=data
556                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_MB")
557                                Wave det_MB=data
558
559                                CheckDisplayed /W=VSANS_Data#det_panelsM det_MR
560                                if(V_flag == 0)
561                                        AppendImage/W=VSANS_Data#det_panelsM det_MT             //order is important here to get LR on "top" of display
562                                        AppendImage/W=VSANS_Data#det_panelsM det_MB
563                                        AppendImage/W=VSANS_Data#det_panelsM det_ML
564                                        AppendImage/W=VSANS_Data#det_panelsM det_MR
565                                        lo_MT = lo*(WaveMax(det_MT) - WaveMin(det_MT)) + WaveMin(det_MT)
566                                        hi_MT = hi*(WaveMax(det_MT) - WaveMin(det_MT)) + WaveMin(det_MT)
567                                        lo_MB = lo*(WaveMax(det_MB) - WaveMin(det_MB)) + WaveMin(det_MB)
568                                        hi_MB = hi*(WaveMax(det_MB) - WaveMin(det_MB)) + WaveMin(det_MB)
569                                        lo_ML = lo*(WaveMax(det_ML) - WaveMin(det_ML)) + WaveMin(det_ML)
570                                        hi_ML = hi*(WaveMax(det_ML) - WaveMin(det_ML)) + WaveMin(det_ML)
571                                        lo_MR = lo*(WaveMax(det_MR) - WaveMin(det_MR)) + WaveMin(det_MR)
572                                        hi_MR = hi*(WaveMax(det_MR) - WaveMin(det_MR)) + WaveMin(det_MR)
573                                       
574                                        ModifyImage/W=VSANS_Data#det_panelsM ''#0 ctab= {lo_MT,hi_MT,ColdWarm,0}                // ''#n means act on the nth image (there are 4)
575                                        ModifyImage/W=VSANS_Data#det_panelsM ''#1 ctab= {lo_MB,hi_MB,ColdWarm,0}
576                                        ModifyImage/W=VSANS_Data#det_panelsM ''#2 ctab= {lo_ML,hi_ML,ColdWarm,0}
577                                        ModifyImage/W=VSANS_Data#det_panelsM ''#3 ctab= {lo_MR,hi_MR,ColdWarm,0}
578                                endif
579                                MoveSubWindow/W=VSANS_Data#det_panelsM fnum=(50,185,517,620)
580                                MoveSubWindow/W=VSANS_Data#det_panelsB fnum=(440,70,550,160)
581                                MoveSubWindow/W=VSANS_Data#det_panelsF fnum=(200,70,310,160)
582
583                                ModifyImage/W=VSANS_Data#det_panelsM ''#0 ctabAutoscale=0,lookup= LookupWave
584                                ModifyImage/W=VSANS_Data#det_panelsM ''#1 ctabAutoscale=0,lookup= LookupWave
585                                ModifyImage/W=VSANS_Data#det_panelsM ''#2 ctabAutoscale=0,lookup= LookupWave
586                                ModifyImage/W=VSANS_Data#det_panelsM ''#3 ctabAutoscale=0,lookup= LookupWave
587                               
588                                // make the plot square
589                                ModifyGraph/W=VSANS_Data#det_panelsM width={Aspect,1}
590                                                       
591                                SetActiveSubWindow VSANS_Data#det_panelsM
592                                SetDataFolder root:
593                        endif
594
595                        if(tab==0)
596                                tmpStr = ImageNameList("VSANS_Data#det_panelsF",";")
597                                // for some odd reason, it appears that I need to work from the back of the list
598                                // since the traces get "renumbered" as I take them off !! A do loop may be a better choice
599                                if(ItemsInList(tmpStr) > 0)
600                                        do
601                                                RemoveImage /W=VSANS_Data#det_panelsF $(StringFromList(0,tmpStr,";"))           //get 1st item
602                                                tmpStr = ImageNameList("VSANS_Data#det_panelsF",";")                                                            //refresh list
603                                        while(ItemsInList(tmpStr) > 0)
604                                endif
605
606                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_FL")
607                                Wave det_FL=data
608                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_FR")
609                                Wave det_FR=data
610                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_FT")
611                                Wave det_FT=data                               
612                                SetDataFolder $("root:Packages:NIST:VSANS:"+dataType+":entry:instrument:detector_FB")
613                                Wave det_FB=data
614                                                               
615                                CheckDisplayed /W=VSANS_Data#det_panelsF det_FL
616                                if(V_flag == 0)
617                                        AppendImage/W=VSANS_Data#det_panelsF det_FT
618                                        AppendImage/W=VSANS_Data#det_panelsF det_FB
619                                        AppendImage/W=VSANS_Data#det_panelsF det_FL
620                                        AppendImage/W=VSANS_Data#det_panelsF det_FR
621                                        lo_FT = lo*(WaveMax(det_FT) - WaveMin(det_FT)) + WaveMin(det_FT)
622                                        hi_FT = hi*(WaveMax(det_FT) - WaveMin(det_FT)) + WaveMin(det_FT)
623                                        lo_FB = lo*(WaveMax(det_FB) - WaveMin(det_FB)) + WaveMin(det_FB)
624                                        hi_FB = hi*(WaveMax(det_FB) - WaveMin(det_FB)) + WaveMin(det_FB)
625                                        lo_FL = lo*(WaveMax(det_FL) - WaveMin(det_FL)) + WaveMin(det_FL)
626                                        hi_FL = hi*(WaveMax(det_FL) - WaveMin(det_FL)) + WaveMin(det_FL)
627                                        lo_FR = lo*(WaveMax(det_FR) - WaveMin(det_FR)) + WaveMin(det_FR)
628                                        hi_FR = hi*(WaveMax(det_FR) - WaveMin(det_FR)) + WaveMin(det_FR)
629                                       
630                                        ModifyImage/W=VSANS_Data#det_panelsF ''#0 ctab= {lo_FT,hi_FT,ColdWarm,0}
631                                        ModifyImage/W=VSANS_Data#det_panelsF ''#1 ctab= {lo_FB,hi_FB,ColdWarm,0}
632                                        ModifyImage/W=VSANS_Data#det_panelsF ''#2 ctab= {lo_FL,hi_FL,ColdWarm,0}
633                                        ModifyImage/W=VSANS_Data#det_panelsF ''#3 ctab= {lo_FR,hi_FR,ColdWarm,0}
634                                endif
635                                MoveSubWindow/W=VSANS_Data#det_panelsF fnum=(50,185,517,620)
636                                MoveSubWindow/W=VSANS_Data#det_panelsB fnum=(440,70,550,160)
637                                MoveSubWindow/W=VSANS_Data#det_panelsM fnum=(320,70,430,160)
638                               
639                                ModifyImage/W=VSANS_Data#det_panelsF ''#0 ctabAutoscale=0,lookup= LookupWave
640                                ModifyImage/W=VSANS_Data#det_panelsF ''#1 ctabAutoscale=0,lookup= LookupWave
641                                ModifyImage/W=VSANS_Data#det_panelsF ''#2 ctabAutoscale=0,lookup= LookupWave
642                                ModifyImage/W=VSANS_Data#det_panelsF ''#3 ctabAutoscale=0,lookup= LookupWave
643
644                                // make the plot square
645                                ModifyGraph/W=VSANS_Data#det_panelsF width={Aspect,1}                           
646       
647                                SetActiveSubWindow VSANS_Data#det_panelsF
648                                SetDataFolder root:
649                        endif
650
651                                               
652                        break
653                case -1: // control being killed
654                        break
655        endswitch
656
657        return 0
658End
659
660// fake restore panels button click
661Function V_FakeRestorePanelsButtonClick()
662
663        STRUCT WMButtonAction ba
664        ba.eventCode = 2
665        V_RestorePanelButtonProc(ba)
666       
667        return(0)
668End
669
670
671// fake status button click
672Function V_FakeStatusButtonClick()
673
674        STRUCT WMButtonAction ba
675        ba.eventCode = 2
676        V_StatusButtonProc(ba)
677       
678        return(0)
679End
680
681// fake click on each tab to populate the data
682Function V_FakeTabClick(tab)
683        Variable tab
684       
685        STRUCT WMTabControlAction tca
686
687        tca.eventCode = 2               //fake mouse up
688        tca.tab = tab
689        V_DataTabProc(tca)
690       
691        TabControl tab0,win=VSANS_Data,value= tab               //select the proper tab
692        return(0)
693End
694
695// TODO
696//
697// move one file number back
698//
699Function V_File_minus_ButtonProc(ba) : ButtonControl
700        STRUCT WMButtonAction &ba
701
702        switch( ba.eventCode )
703                case 2: // mouse up
704                        // click code here
705                        V_LoadPlotAndDisplayRAW(-1)
706                       
707                        break
708                case -1: // control being killed
709                        break
710        endswitch
711
712        return 0
713End
714
715// TODO
716//
717// move one file number forward
718//
719Function V_File_plus_ButtonProc(ba) : ButtonControl
720        STRUCT WMButtonAction &ba
721
722        switch( ba.eventCode )
723                case 2: // mouse up
724                        // click code here
725                        V_LoadPlotAndDisplayRAW(1)
726
727                        break
728                case -1: // control being killed
729                        break
730        endswitch
731
732        return 0
733End
734
735//
736// button that mimics a click on the tab, cycling through the tabs 0->1->2->0 etc.
737// only goes one direction
738//
739Function V_Tab_p_ButtonProc(ba) : ButtonControl
740        STRUCT WMButtonAction &ba
741
742        switch( ba.eventCode )
743                case 2: // mouse up
744                        // click code here
745                        ControlInfo/W=VSANS_Data tab0
746                       
747                        V_Value += 1
748                        if(V_Value == 3)
749                                V_Value = 0             //reset to 0
750                        endif
751                        V_FakeTabClick(V_Value)
752
753// update the status when the tab is clicked                   
754                        STRUCT WMButtonAction sa
755                        sa.eventCode = 2
756                        V_StatusButtonProc(sa)
757
758                        break
759                case -1: // control being killed
760                        break
761        endswitch
762
763        return 0
764End
765
766
767// See V_Detector_Isolate.ipf
768// isolates a single panel to allow a better view of the details
769// useful for T/B panels which are partially blocked from view
770//
771// will open a separate panel to display the selected detector
772// (more to do here, depending what is necessary for instrument troubleshooting)
773// - like being able to turn corrections on/off and view with different axes (pix, mm, Q)
774//
775Function V_IsolateButtonProc(ba) : ButtonControl
776        STRUCT WMButtonAction &ba
777
778        switch( ba.eventCode )
779                case 2: // mouse up
780                        // click code here
781                        V_DetectorIsolate()
782                        break
783                case -1: // control being killed
784                        break
785        endswitch
786
787        return 0
788End
789
790//
791// if the data display is RAW, convert to the specified WORK data type
792//
793// TODO
794// -- better error checking
795// -- if the data type is not RAW, can I Copy Folder instead?
796//
797Function V_ToWorkFileButtonProc(ba) : ButtonControl
798        STRUCT WMButtonAction &ba
799
800        switch( ba.eventCode )
801                case 2: // mouse up
802                        // click code here
803                        //Convert_to_Workfile(newtype, doadd) // a proc
804                        Execute "V_Convert_to_Workfile()"
805
806                        break
807                case -1: // control being killed
808                        break
809        endswitch
810
811        return 0
812End
813
814
815// TODO
816//
817// opens a separate panel with the I(q) representation of the data
818// ? controls here to select how the data is processed/grouped/saved, etc.
819//
820// -- currently just the graph, no controls
821// -- this re-bins the data every time by calling V_QBinAllPanels(folderStr,binType)
822Function V_IvsQPanelButtonProc(ba) : ButtonControl
823        STRUCT WMButtonAction &ba
824
825        switch( ba.eventCode )
826                case 2: // mouse up
827                        // click code here
828                       
829                        V_PlotData_Panel()              //-9999 requests a read from the popup on the panel
830                        Variable binType = V_GetBinningPopMode()
831                        V_BinningModePopup("",binType,"")               // does default circular binning and updates the graph
832                       
833                        break
834                case -1: // control being killed
835                        break
836        endswitch
837
838        return 0
839End
840
841// TODO
842//
843// gets the status of the currently displayed file and dumps it to the panel (not the cmd window)
844// - lots to decide here about what is the important stuff to display. There's a lot more information for VSANS
845//
846Function V_StatusButtonProc(ba) : ButtonControl
847        STRUCT WMButtonAction &ba
848
849        switch( ba.eventCode )
850                case 2: // mouse up
851                        // click code here
852                       
853                        // figure out wether to display per carraige, or the whole file
854                        SVAR str = root:Packages:NIST:VSANS:Globals:gStatusText
855                        SVAR type = root:Packages:NIST:VSANS:Globals:gCurDispType               //what folder
856                        // which tab active
857                        ControlInfo/W=VSANS_Data tab0
858                        Variable curTab = V_value
859                       
860                        str = "Current data is from "+ type + "\r"
861                        str += "Description = "+V_getSampleDescription(type) + "\r"
862                        str += "Wavelength is "+num2str(V_getWavelength(type)) + " A \r"
863                        if(curTab == 2)
864                                str += "SDD B = "+num2str(V_getDet_ActualDistance(type,"B")) + " cm \r"         //V_getDet_distance(fname,detStr)
865                        endif
866                        if(curTab == 1)
867                                str += "SDD ML = "+num2str(V_getDet_ActualDistance(type,"ML")) + " cm \r"
868                                str += "SDD MR = "+num2str(V_getDet_ActualDistance(type,"MR")) + " cm \r"
869                                str += "SDD MT = "+num2str(V_getDet_ActualDistance(type,"MT")) + " cm \r"
870                                str += "SDD MB = "+num2str(V_getDet_ActualDistance(type,"MB")) + " cm \r"
871                        endif
872                        if(curTab == 0)
873                                str += "SDD FL = "+num2str(V_getDet_ActualDistance(type,"FL")) + " cm \r"
874                                str += "SDD FR = "+num2str(V_getDet_ActualDistance(type,"FR")) + " cm \r"
875                                str += "SDD FT = "+num2str(V_getDet_ActualDistance(type,"FT")) + " cm \r"
876                                str += "SDD FB = "+num2str(V_getDet_ActualDistance(type,"FB")) + " cm \r"
877                        endif
878                       
879                       
880                       
881                       
882                       
883                        break
884                case -1: // control being killed
885                        break
886        endswitch
887
888        return 0
889End
890
891
892// TODO:
893// x- link this to the preferences for the display. this is done in UpdateDisplayInformation (the main call) so that
894//     the panels are rescaled only once, rather than toggled three times (F, M, B) if I call from the tabProc
895// -- come up with a better definition of the log lookup wave (> 1000 pts, what is the first point)
896// -- make an equivalent linear wave
897// -- hard wire it in so it is created at initialization and stored someplace safe
898// -- catch the error if it doesn't exist (re-make the wave as needed)
899//
900// Using the ModifyImage log=1 keyword fails for values of zero in the data, which is a common
901// occurrence with count data. the display just goes all gray, so that's not an option. Use the lookup wave instead
902//
903// toggle the (z) value of the display log/lin
904//
905Function V_LogLinButtonProc(ba) : ButtonControl
906        STRUCT WMButtonAction &ba
907
908        switch( ba.eventCode )
909                case 2: // mouse up
910                        // click code here
911                       
912                        // which tab is active? does it matter - or do I log-scale everything?
913                        // log/lin current state is in the S_UserData string (0=linear, 1=log)
914                        ControlInfo/W=VSANS_Data button_log
915                        Variable curState,newState
916                        String newStateStr,newTitleStr
917                       
918                       
919                        curState = str2num(S_UserData)
920                       
921                        if(curState == 0)
922                                newState = 1
923                                newStateStr="1"
924                                newTitleStr = "isLog"
925                                // lookup wave
926                                Wave LookupWave = root:Packages:NIST:VSANS:Globals:logLookupWave
927                        else
928                                newState = 0
929                                newStateStr="0"
930                                newTitleStr = "isLin"
931                                // lookup wave - the linear version
932                                Wave LookupWave = root:Packages:NIST:VSANS:Globals:linearLookupWave
933                        endif
934                       
935                        // update the button and the global value
936                        Button button_log,userData=newStateStr,title=newTitleStr
937                        NVAR state = root:Packages:NIST:VSANS:Globals:gIsLogScale
938                        state = newState
939                       
940                        // on the front:                       
941                        ModifyImage/W=VSANS_Data#det_panelsF ''#0 ctabAutoscale=0,lookup= LookupWave
942                        ModifyImage/W=VSANS_Data#det_panelsF ''#1 ctabAutoscale=0,lookup= LookupWave
943                        ModifyImage/W=VSANS_Data#det_panelsF ''#2 ctabAutoscale=0,lookup= LookupWave
944                        ModifyImage/W=VSANS_Data#det_panelsF ''#3 ctabAutoscale=0,lookup= LookupWave
945                        //on the middle:
946//                      ModifyImage/W=VSANS_Data#det_panelsM ''#0 log=newState
947//                      ModifyImage/W=VSANS_Data#det_panelsM ''#1 log=newState
948//                      ModifyImage/W=VSANS_Data#det_panelsM ''#2 log=newState
949//                      ModifyImage/W=VSANS_Data#det_panelsM ''#3 log=newState
950                               
951                        ModifyImage/W=VSANS_Data#det_panelsM ''#0 ctabAutoscale=0,lookup= LookupWave
952                        ModifyImage/W=VSANS_Data#det_panelsM ''#1 ctabAutoscale=0,lookup= LookupWave
953                        ModifyImage/W=VSANS_Data#det_panelsM ''#2 ctabAutoscale=0,lookup= LookupWave
954                        ModifyImage/W=VSANS_Data#det_panelsM ''#3 ctabAutoscale=0,lookup= LookupWave
955
956
957                        // on the back:
958                        ModifyImage/W=VSANS_Data#det_panelsB ''#0 ctabAutoscale=0,lookup= LookupWave
959
960                        break
961                case -1: // control being killed
962                        break
963        endswitch
964
965        return 0
966End
967
968// TODO
969// possibly function to "tag" files right here in the disaply with things
970// like their intent, or other values that reduction will need, kind of like a "quick patch"
971// with limited functionality (since full function would be a nightmare!)
972Function V_TagFileButtonProc(ba) : ButtonControl
973        STRUCT WMButtonAction &ba
974
975        switch( ba.eventCode )
976                case 2: // mouse up
977                        // click code here
978                        DoAlert 0, "TagFileButtonProc(ba) unfinished - this may be used to 'tag' a file as scatter, trans, emp, bkg, etc."
979                       
980                               
981                        break
982                case -1: // control being killed
983                        break
984        endswitch
985
986        return 0
987End
988
989// TODO
990// -- fill in more functionality
991// -- currently a straight concatentation of all data, no options
992// -- maybe allow save of single panels?
993// -- any other options?
994Function V_SaveIQ_ButtonProc(ba) : ButtonControl
995        STRUCT WMButtonAction &ba
996
997        switch( ba.eventCode )
998                case 2: // mouse up
999                        // click code here
1000
1001                        V_SimpleSave1DData("","")               
1002                               
1003                        break
1004                case -1: // control being killed
1005                        break
1006        endswitch
1007
1008        return 0
1009End
1010
1011//TODO
1012//
1013//link this to the beam center finding panel
1014//
1015Function V_BeamCtrButtonProc(ba) : ButtonControl
1016        STRUCT WMButtonAction &ba
1017
1018        switch( ba.eventCode )
1019                case 2: // mouse up
1020                        // click code here
1021                        V_FindBeamCenter()
1022                        break
1023                case -1: // control being killed
1024                        break
1025        endswitch
1026
1027        return 0
1028End
1029
1030//TODO
1031//
1032// this "spreads" the display of panels to a nominal separation for easier viewing
1033//
1034Function V_SpreadPanelButtonProc(ba) : ButtonControl
1035        STRUCT WMButtonAction &ba
1036
1037        switch( ba.eventCode )
1038                case 2: // mouse up
1039                        // click code here
1040                        V_SpreadOutPanels()
1041                       
1042                        break
1043                case -1: // control being killed
1044                        break
1045        endswitch
1046
1047        return 0
1048End
1049
1050//TODO
1051//
1052// this "restores" the display of panels to their actual position based on the apparent beam center
1053//
1054Function V_RestorePanelButtonProc(ba) : ButtonControl
1055        STRUCT WMButtonAction &ba
1056
1057        switch( ba.eventCode )
1058                case 2: // mouse up
1059                        // click code here
1060                        V_RestorePanels()
1061                               
1062                        break
1063                case -1: // control being killed
1064                        break
1065        endswitch
1066
1067        return 0
1068End
1069
1070// TODO
1071//
1072// link this slider to the "high" end of the color mapping for whatever is currently displayed
1073//
1074// -- see Buttons.ipf for the old SANS implementation
1075//
1076Function V_HiMapSliderProc(sa) : SliderControl
1077        STRUCT WMSliderAction &sa
1078
1079        switch( sa.eventCode )
1080                case -1: // control being killed
1081                        break
1082                default:
1083                        if( sa.eventCode & 1 ) // value set
1084                                Variable curval = sa.curval
1085                                ControlInfo tab0
1086                                V_FakeTabClick(V_Value)
1087                               
1088//                              ControlInfo slider_lo
1089//                              V_MakeImageLookupTables(10000,V_Value,curval)
1090                        endif
1091                        break
1092        endswitch
1093
1094        return 0
1095End
1096
1097// TODO
1098//
1099// link this slider to the "low" end of the color mapping for whatever is currently displayed
1100//
1101// -- see Buttons.ipf for the old SANS implementation
1102//
1103Function V_LowMapSliderProc(sa) : SliderControl
1104        STRUCT WMSliderAction &sa
1105
1106        switch( sa.eventCode )
1107                case -1: // control being killed
1108                        break
1109                default:
1110                        if( sa.eventCode & 1 ) // value set
1111                                Variable curval = sa.curval
1112                                ControlInfo tab0
1113                                V_FakeTabClick(V_Value)
1114
1115//                              ControlInfo slider_hi
1116//                              V_MakeImageLookupTables(10000,curval,V_Value)
1117                        endif
1118                        break
1119        endswitch
1120
1121        return 0
1122End
1123
1124
Note: See TracBrowser for help on using the repository browser.