listbox problem

I am facing a problem related to a listbox. The listbox resides in an external panel of a host panel and lists wave names. The corresponding waves are appended to a graph of the host panel when the listbox entry is clicked. This is established by a strucure-based action procedure (case 4 of lba.eventCode).
The problem is: When I set a cursor an a trace of the graph, I can't move this cursor by the keyboard arrow keys, also CMD-A for SetAxis/A does not work any longer. It seems that all keyboard strokes are intercepted by the listbox action procedure. I tried setting the active subwindow to the host window of the listbox panel, but without success.
Any hints are much appreciated.
I am using IP 6.10B06 on a MB Pro.
awirsing wrote:
It seems that all keyboard strokes are intercepted by the listbox action procedure.


I could not reproduce this exactly, but noticed something curious that may be related.

Using the "default" ListBox Action Procedure (obtained by clicking on the "new" button in the dialog that opens when you double-click on an existing listbox control), my IP6.10B06 (Win) responded to keyboard strokes (at least to the arrow keys). This however relied on the graph window being the active subwindow (achieved by clicking on it). I let Igor figure out how to set the active subwindow properly, i.e. I looked at the Graph0 recreation macro generated by Igor.

I noticed something funny: Even with the active subwindow set up with the command SetActiveSubwindow ##, the cursor was redrawn in the exterior panel. I had to add a ShowInfo;HideInfo sequence to prevent this. You can find these two behaviors in the snippet below. Paste this into your Procedure window and choose "start1" or "start2" from the Macros menu.

Cheers,
Wolfgang Harneit

#pragma rtGlobals=1     // Use modern global access method.

Macro Start1()
    make/O w={1,2,4,5}
    display w
    Cursor A w 1
    Make/T/O tw={"abc","def"}
    Graph1()
End

Macro Start2()
    make/O w={1,2,4,5}
    display w
    Cursor A w 1
    Make/T/O tw={"abc","def"}
    Graph2()
End

Function ListBoxProc(lba) : ListBoxControl
    STRUCT WMListboxAction &lba
    return 0
End

Window Graph1() : Graph
    PauseUpdate; Silent 1       // building window...
    Display /W=(35.25,42.5,429.75,251) w
    Cursor/P A w 0
    NewPanel/HOST=#/EXT=0/W=(0,0,217,278)
    ListBox list0,pos={1,2},size={150,103},proc=ListBoxProc,listWave=root:tw
    RenameWindow #,P0
    SetActiveSubwindow ##
    ShowInfo
    HideInfo
EndMacro

Window Graph2() : Graph
    PauseUpdate; Silent 1       // building window...
    Display /W=(35.25,42.5,429.75,251) w
    Cursor/P A w 0
    NewPanel/HOST=#/EXT=0/W=(0,0,217,278)
    ListBox list0,pos={1,2},size={150,103},proc=ListBoxProc,listWave=root:tw
    RenameWindow #,P0
    SetActiveSubwindow ##
//  ShowInfo
//  HideInfo
EndMacro
I should had provided an example to clear things...
To illustrate the problem paste my snippet in the procedure window and choose Start3 from the macro menu.
I couldn't find a way to move the cursor by means of the keyboard's arrow keys. Hitting these keys invokes the listbox action procedure once you clicked in the listbox as you can see by the prints in the history although the active subwindow is set to the host window.

Macro Start3() : Graph
    make/O w1={1,2,4,5}
    make/O w2={5,4,2,3}
    Make/T/O tw={"w1","w2"}
    Graph3()
End

Window Graph3() : Graph
    PauseUpdate; Silent 1       // building window...
    Display /W=(155,82,550,290) w1
    Cursor/P A w1 0
    NewPanel/HOST=#/EXT=1/W=(0,0,15,100)/K=2
    ListBox list0,pos={1,2},size={150,103},mode=1,selrow=-1,proc=ListBoxProc3,listWave=tw
    RenameWindow #,P0
    SetActiveSubwindow ##
    ShowInfo
EndMacro

Function ListBoxProc3(lba) : ListBoxControl
    STRUCT WMListboxAction &lba

    Variable row = lba.row
    WAVE/T/Z listWave = lba.listWave

    switch( lba.eventCode )
        case 4: // cell selection
            switch(row)
                case 0:
                    print "case 0"
                    removefromgraph $removeending(tracenamelist("",",",1))
                    appendtograph $(listwave[0])
                    DoUpdate
                    cursor/p a $(listwave[0]) 1
                break
                case 1:
                    print "case 1"
                    removefromgraph $removeending(tracenamelist("",",",1))
                    appendtograph $(listwave[1])
                    DoUpdate
                    cursor/p a $(listwave[1]) 2
                break
            endswitch
        break
    endswitch

    return 0
End

@ Wolfgang: Also your Showinfo;Hideinfo trick doesn't aktually solve the problem. Once you click on the listbox moving the cursor with the arrow keys is disabled. This applies to both cases (Start1 and Start2).
I just did a quick & dirty hack to solve the issue. Now you can use the left/right arrow keys (or the mouse) to move the cursor and the up/down arrow keys (or the mouse) to operate the listbox control. The code is not so nice (e.g., too many hardwired references to "Graph3"), and may be fragile (see below). I did not get around to comment the code, please tell me if you want more documentation.

Details: in order to get the keyboard focus off the listbox control, I just put a dummy button somewhere in your panel where it can't be seen (some dirty trick). That was the "easy" part - the cursor immediately starts to respond. But the listbox is then definitely not responding to keyboard strokes anymore. So I tried to remedy that by introducing a window hook for the graph window that catches the keyboard strokes. Also quite easy. But then I had to come up with an update mechanism and I wanted to keep the listbox control synchronized with the updates. That was quite hard, and may be the fragile part. Please test & comment.
Wolfgang Harneit

Macro Start3() : Graph
    make/O w1={1,2,4,5}
    make/O w2={5,4,2,3}
    Make/T/O tw={"w1","w2"}
    Variable/G root:recentlyDisplayedWave = 0
    Make/O/N=(numpnts(tw)) cursorPositions=0
    Graph3()
End
 
Window Graph3() : Graph
    PauseUpdate; Silent 1       // building window...
    Display /W=(155,82,550,290) w1
    Cursor/P A w1 0
    NewPanel/HOST=#/EXT=1/W=(0,0,15,100)/K=2
    ListBox list0,pos={1,2},size={150,103},mode=1,selrow=0,proc=ListBoxProc3,listWave=tw
    RenameWindow #,P0
    SetActiveSubwindow ##
    ShowInfo
    SetWindow Graph3, hook(myhook)=GraphWinHook
EndMacro
 
Function ListBoxProc3(lba) : ListBoxControl
    STRUCT WMListboxAction &lba
    Variable row = lba.row
    WAVE/T/Z listWave = lba.listWave
    NVAR oldRow = root:recentlyDisplayedWave
    switch( lba.eventCode )
        case 4: // cell selection
            if( oldRow != row )
                SwapWaves(oldRow, row, listWave)
                oldRow = row
            endif
        break
    endswitch
    return 0
End

function SwapWaves(oldRow, newRow, listWave)
variable oldRow, newRow
Wave/T listWave
    WAVE cursorPos = root:cursorPositions
    cursorPos[oldRow] = pcsr(A)
    RemoveFromGraph/W=Graph3 $(listWave[oldRow])
    AppendToGraph/W=Graph3 $(listWave[newRow])
    Cursor/p a $(listWave[newRow]) cursorPos[newRow]
    Button dummy,pos={200,200},win=Graph3#P0    // makes listbox control lose keyboard focus
    DoUpdate
end

function GraphWinHook(whs)
struct WMWinHookStruct &whs
    if( whs.eventCode == 11 && (whs.keycode == 30 || whs.keycode == 31) )
        ControlInfo/W=Graph3#P0 list0
        wave/T listWave = $S_value
        variable oldRow = V_Value, newRow
        if( whs.keycode == 30 ) // cursor up
            newRow = max(0, oldRow - 1)
        else                        // cursor down
            newRow = min(numpnts(listWave) - 1, oldRow + 1)
        endif
        SwapWaves(oldRow, newRow, listWave)
        ListBox list0, selRow= newRow, win= Graph3#P0
    endif
end
Thank you, Wolfgang. Your hack seems to work. The Start3 example was naturally only kept so simple to illustrate the issue properly.
For my purpose I established another quick and dirty solution: Clicking the listbox kills the external panel and I put a button on the host panel which invokes the external panel (and the listbox) again. I have anyway a lot of buttons on the host panel, so one more doesn't hurt. Thanks again, Wolfgang, for your effort.
This is clearly a bug in the Listbox control- it should relinquish the keyboard focus when the graph becomes the active window. But establishing that the graph is the active window is somewhat more complicated when the listbox is in an exterior panel attached to the graph.

I will put this on my list of things to look into.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
I seem to have the same problem (I can not get rid of the keyboard focus on the listbox, which sits in an exterior subwindow of a graph).
Are there any news on this issue?

I'm using Igor 6.21 on Windows XP SP3.
thomas_braun wrote:
Are there any news on this issue?


There are.
I had an off-list discussion with John several months ago. He suggested to disable the listbox temporarily:
    ListBox theList,win=pathToThe#ExtWin,disable=1
    ListBox theList,win=pathToThe#ExtWin,disable=0

This worked for me very nicely and replaced my 100-line workaround by just 2 lines.

A