Clarion 9's list box sorting

Clarion 9 appears to add support for list box sorting, so I decided to give it a whirl. '

The new bits I'm aware of are some properties:

PROPLIST:DefHdrTextColor  EQUATE (7C2AH) ! integer: Text color in header
PROPLIST:DefHdrBackColor  EQUATE (7C2BH) ! integer: Background color in header
PROPLIST:HdrSortTextColor EQUATE (7C2CH) ! integer: Text color in header of sort column
PROPLIST:HdrSortBackColor EQUATE (7C2DH) ! integer: Background color in header of sort column
PROPLIST:SortTextColor    EQUATE (7C2EH) ! integer: Text color of sort column
PROPLIST:SortBackColor    EQUATE (7C2FH) ! integer: Background color of sort column
PROPLIST:HasSortColumn    EQUATE (7C30H) ! boolean: TRUE if sort column is supported
PROPLIST:SortColumn       EQUATE (7C31H) ! integer: Current sort column

and a new event:

EVENT:HeaderPressed EQUATE (1FH)

I put together a small demo app:

                                        PROGRAM

                                        MAP
                                        END
    INCLUDE('equates.clw'),ONCE 
DataQ                                   QUEUE
Column1                                     string(20)
Column2                                     long
Column3                                     string(20)
                                        END
x                                       LONG

MyWindow                                WINDOW('Caption'),AT(,,336,285),GRAY,FONT('MS Sans Serif',8,,FONT:regular)
                                            BUTTON('&Close'),AT(287,262,36,14),USE(?CancelButton),LEFT
                                            LIST,AT(15,8,307,243),USE(?LIST),VSCROLL,FROM(dataq),FORMAT('100L(2)|M~C' & |
                                                'olumn 1~100L(2)|M~Column 2~100L(2)|M~Column 3~')
                                        END

    CODE
 
    ! Create some dummy data 
    loop 100 TIMES
        loop x = 1 to 20
            DataQ.Column1[x] = chr(random(65,122))
            DataQ.Column3[x] = chr(random(65,122))
        END
        Dataq.Column2 = random(1,10000)
        add(dataq)
    END
    
    OPEN(MyWindow)
    ACCEPT
        case event()
        of EVENT:HeaderPressed
            0{prop:text} = 'Current sort column: ' & ?list{PROPLIST:SortColumn}
        END
        
        CASE FIELD()
        OF 0
            CASE EVENT()
            OF EVENT:OpenWindow
            END
        OF ?CancelButton
            CASE EVENT()
            OF EVENT:Accepted
                POST(EVENT:CloseWindow)
            END
        END
    END
 

I ran the app, but I didn't notice anything different about the list box. It didn't sort on columns or produce any header pressed events. For a moment I thought maybe I needed an IMM attribute, but of course that removes all of the built in event handling including scrolling, so I took it right back off again. 

Here's the sample app:

Then I realized that I was missing the PROPLIST assignments in my code. I added them to the OpenWindow event handling:

            CASE EVENT()
            OF EVENT:OpenWindow
                ?list{PROPLIST:HasSortColumn,1} = true
                ?list{PROPLIST:HasSortColumn,2} = true
                ?list{PROPLIST:HasSortColumn,3} = true
            END

That triggered EVENT:HeaderPressed, but no automatic sorting. Well, that's not a big deal. I added this code:

            case ?list{PROPLIST:SortColumn}
            of 1
                sort(dataq,dataq.Column1)
            of 2
                sort(dataq,dataq.Column2)
            of 3
                sort(dataq,dataq.Column3)
            END

Presto - list box sorting:

I also added some code to set PROPLIST:HdrSortTextColor and PROPLIST:SortTextColor for visual clues. 

But there are some oddities. Header coloring isn't always cleared when you select another column, and at the start all column headers are colored. Also the first click on a header changes the color, but the sorting doesn't happen until the second click, which can happen at any time after the first click (i.e. it's not a true double click). Here I've clicked on Column 2 but the sort order is still Column 3. 

After playing around with this a bit more I realized that the problem is that PROPLIST:SortColumn doesn't return the column you just selected, it returns the column previously set as the sort column. Either there's a bug there or I'm handling the event wrong. 

There doesn't seem to be any way internally to track the state of the sort order (i.e. if you want ascending/descending), so at present you'd need to do that in your own code. Also I don't see a means to add an image to indicate the sort order. There are ways to do that already, as Randy Rogers showed in ClarionMag, but they're non-trivial. 

While not a complete solution to sorting list boxes, Clarion 9 offers a good if slightly buggy start. I'd love to see a property for a sort order indicator image and some internal toggle tracking to go with it,. 

Here's the complete source for the sample Clarion 9 program:

                                        PROGRAM

                                        MAP
                                        END
    INCLUDE('equates.clw'),ONCE 
DataQ                                   QUEUE
Column1                                     string(20)
Column2                                     long
Column3                                     string(20)
                                        END
x                                       LONG

MyWindow                                WINDOW('Caption'),AT(,,336,285),GRAY,FONT('MS Sans Serif',8,,FONT:regular)
                                            BUTTON('&Close'),AT(287,262,36,14),USE(?CancelButton),LEFT
                                            LIST,AT(15,8,307,243),USE(?LIST),VSCROLL,FROM(dataq),FORMAT('100L(2)|M~C' & |
                                                'olumn 1~100L(2)|M~Column 2~100L(2)|M~Column 3~')
                                        END
    CODE
    loop 100 TIMES
        loop x = 1 to 20
            DataQ.Column1[x] = chr(random(65,122))
            DataQ.Column3[x] = chr(random(65,122))
        END
        Dataq.Column2 = random(1,10000)
        add(dataq)
    END
    
    OPEN(MyWindow)
    ACCEPT
        case event()
        of EVENT:HeaderPressed
            0{prop:text} = 'Current sort column: ' & ?list{PROPLIST:SortColumn}
            case ?list{PROPLIST:SortColumn}
            of 1
                sort(dataq,dataq.Column1)
            of 2
                sort(dataq,dataq.Column2)
            of 3
                sort(dataq,dataq.Column3)
            END
        END
        
        CASE FIELD()
        OF 0
            CASE EVENT()
            OF EVENT:OpenWindow
                ?list{PROPLIST:HasSortColumn,1} = true
                ?list{PROPLIST:HasSortColumn,2} = true
                ?list{PROPLIST:HasSortColumn,3} = true
                ?list{PROPLIST:HdrSortTextColor} = color:blue
                !?list{PROPLIST:HdrSortBackColor} = color:yellow
                ?list{PROPLIST:SortTextColor} = color:blue
                !?list{PROPLIST:SortBackColor} = color:yellow
            END
        OF ?CancelButton
            CASE EVENT()
            OF EVENT:Accepted
                POST(EVENT:CloseWindow)
            END
        END
    END