home *** CD-ROM | disk | FTP | other *** search
- /*
- Listing 14.11 Very Fancy ACHOICE() Menu
- Author: Greg Lief
- Excerpted from Grumpfish Library's APICK() Function
- Copyright (c) 1988-91 Greg Lief
- Distributed by Grumpfish Inc., Box 17761, Salem, OR 97305 USA (503) 588-1815
- */
-
- //───── NOTE: must be compiled with the /N compiler option
-
- #include "achoice.ch"
- #include "box.ch"
- #include "inkey.ch"
-
- #define ISCHAR(a) valtype(a) == "C"
- #define K_SPACEBAR 32
- #define CHECKMARK chr(251)
-
- static rel_elem // relative element position in ACHOICE()
- static rel_row // relative row position in ACHOICE()
- static num_opts // length of array - used in ACHOICE()
- static bar_line // current position of elevator indicator
- static stat_clr // color for elevator indicator
- static bar_clr // color for status bar
- static draw_bar // flag for whether or not to draw elevator bar
- static ntop, nleft, nbottom, nright // coordinates for ACHOICE() box
-
- function main
- local nrow := 9, ncol := 25, x, oldcursor := setcursor(0), ;
- oldcolor, cities := {"Baltimore", "Boston", "Detroit", ;
- "New York", "Chicago", "Toronto", "Cleveland", "Milwaukee", ;
- "Texas", "Seattle", "California", "Oakland", "Minnesota", "Kansas City"}
- cls
- gchoice(cities)
- cls
- dispbox(8, 23, 16, 56, B_SINGLE + ' ', 'w/rb')
- @ 8, 30 say "[ Selected Cities ]" color '+w/rb'
- for x = 1 to len(cities)
- if right(cities[x], 1) = CHECKMARK
- @ nrow, ncol say substr(cities[x], 1, len(cities[x]) - 1) color '+w/rb'
- if ncol == 25
- ncol := 42
- else
- ncol := 25
- nrow++
- endif
- endif
- next
- inkey(0)
- setcursor(oldcursor)
- return nil
-
-
- /*
- GCHOICE() - shell for ACHOICE()
- */
- function gchoice
- parameter aarray
- local x, maxwidth := 0, oldcolor, oldscrn, available := {}, ;
- unsel_clr, box_clr, hilite_clr
- num_opts := len(aarray)
-
- //───── determine widest array element and set columns accordingly
- aeval(aarray, { | a | maxwidth := max(maxwidth, len(a)) } )
- nleft := int((maxcol() - 2 - maxwidth) / 2)
- nright := nleft + maxwidth + 2
- //───── determine top and bottom rows based on length of array
- ntop := max(7, 11 - int(num_opts / 2))
- nbottom := maxrow() - ntop
-
- /*
- build a parallel array for available choices by looping through
- the main array - unavailable selections will begin with tilde (~)
- */
- aeval(aarray, { | a | aadd(available, ;
- if(ISCHAR(a), substr(a, 1, 1) != '~', .t.) ) } )
-
- /*
- now we manipulate the elements in the actual array:
- 1) add a space to the end of each array element,
- which will then be used for the checkmark
- 2) strip out tildes
- */
- for x = 1 to num_opts
- if ISCHAR(aarray[x])
- if left(aarray[x], 1) != '~'
- aarray[x] += chr(K_SPACEBAR)
- else
- aarray[x] := substr(aarray[x], 2)
- // see if they want to draw a horizontal line - if so,
- // trimmed length of this array element will now be one.
- if len(trim(aarray[x])) == 1
- aarray[x] := replicate(trim(aarray[x]), maxwidth)
- endif
- endif
- endif
- next
-
- rel_elem := rel_row := 1
- box_clr := '+W/' + if(iscolor(), 'B', 'N')
- bar_clr := 'W/N, I'
- stat_clr := '+GR/N'
- unsel_clr := substr(box_clr, 2)
- hilite_clr := 'I'
- draw_bar := (num_opts > nbottom - ntop - 1)
- //───── force status bar to be drawn on first pass
- bar_line := ntop + 2
- oldcolor := setcolor(box_clr)
- oldscrn := savescreen(ntop, nleft, nbottom, nright)
- @ ntop, nleft, nbottom, nright box B_DOUBLE + ' '
- if draw_bar
- @ ntop + 1, nright, nbottom - 1, nright box chr(176) color bar_clr
- endif
- setcolor(box_clr + ',' + hilite_clr + ',,,' + unsel_clr)
- keyboard chr(255)
- do while .t.
- achoice(ntop + 1, nleft + 1, nbottom - 1, nright - 1,;
- aarray, available, 'keytest', rel_elem, rel_row)
- if lastkey() == K_ENTER .or. lastkey() == K_ESC
- exit
- endif
- enddo
- restscreen(ntop, nleft, nbottom, nright, oldscrn)
- setcolor(oldcolor)
- return NIL
-
-
- /*
- KeyTest() - Handle keystroke exceptions for ACHOICE()
- */
- function KeyTest(status, curr_elem, curr_row)
- memvar aarray
- local xx, oldrow := row(), oldcol := col(), ret_val := AC_CONT, ;
- telem, key := lastkey()
- static searchstr := []
- do case
-
- case status == AC_HITTOP
- rel_elem := num_opts
- keyboard chr(255) // force status bar display
- ret_val := AC_ABORT // force ACHOICE() to restart
-
- case status == AC_HITBOTTOM
- rel_elem := 1
- keyboard chr(255) // force status bar display
- ret_val := AC_ABORT // force ACHOICE() to restart
-
- case status == AC_IDLE .or. key == 255
- if draw_bar
- //───── draw arrows if elements beyond top or bottom of window
- //───── first, the bottom
- @ nbottom, nright say if(num_opts - curr_elem >= nbottom - oldrow, ;
- chr(25), chr(188))
- //───── then the top
- @ ntop, nright say if(oldrow - curr_elem < ntop, chr(24), chr(187))
-
- //───── if status bar position has changed, redraw it now
- if bar_line != ntop + 1 + int((curr_elem / num_opts) * ;
- (nbottom - ntop - 2))
- //───── first, blank out previous status bar
- @ bar_line, nright say chr(176) color bar_clr
- //───── then recalculate position of status bar
- bar_line := ntop + 1 + int( (curr_elem / num_opts) * ;
- (nbottom - ntop - 2) )
- //───── finally, redraw it
- @ bar_line, nright say chr(219) color stat_clr
- endif
- endif
-
- case key == K_SPACEBAR // toggle this element on/off
- aArray[curr_elem] := left(aArray[curr_elem], ;
- len(aArray[curr_elem]) - 1) + ;
- if(right(aArray[curr_elem], 1) == " ", CHECKMARK, " ")
- rel_elem := curr_elem
- rel_row := curr_row
- searchstr := [] // reset search string
- @ nbottom, 36 say replicate(chr(205), 8)
- ret_val := AC_ABORT // Force ACHOICE redisplay
-
- case key == K_ENTER .or. key == K_ESC
- ret_val := AC_ABORT // prepare to fall out
-
- case key == K_HOME
- keyboard chr(K_CTRL_PGUP)
-
- case key == K_END
- keyboard chr(K_CTRL_PGDN)
-
- case key == K_F8 // tag all items
- for xx = 1 to num_opts
- aArray[xx] := left(aArray[xx], len(aArray[xx]) - 1) + CHECKMARK
- next
- rel_elem := curr_elem // save current position
- rel_row := curr_row // and relative position
- ret_val := AC_ABORT // Force ACHOICE redisplay
-
- case key == K_F9 // clear all tags
- for xx = 1 to num_opts
- aArray[xx] := left(aArray[xx], len(aArray[xx]) - 1) + chr(K_SPACEBAR)
- next
- rel_elem := curr_elem // save current position
- rel_row := curr_row // and relative position
- ret_val := AC_ABORT // Force ACHOICE redisplay
-
- case key == K_F10 // reverse all tags
- for xx = 1 TO num_opts
- aArray[xx] := left(aArray[xx], len(aArray[xx]) - 1) + ;
- if(right(aArray[xx], 1) = " ", "√", " ")
- next
- rel_elem := curr_elem // save current position
- rel_row := curr_row // and relative position
- ret_val := AC_ABORT // force ACHOICE redisplay
-
-
- case IsAlpha(chr(key)) // letter key - search
- searchstr += chr(key)
- telem := ascan2(aArray, searchstr)
- rel_elem := if(telem = 0, curr_elem, telem)
- @ nbottom, 36 say "[" + padr(searchstr, 6) + "]"
- ret_val := AC_ABORT // Force ACHOICE redisplay
-
- case key == K_BS .or. key == K_LEFT
- if len(searchstr) > 0
- searchstr := substr(searchstr, 1, len(searchstr) - 1)
- telem := ascan2(aArray, searchstr)
- rel_elem := IF(telem == 0, curr_elem, telem)
- endif
- @ nbottom, 36 say if(len(searchstr) == 0, replicate(chr(205), 8), ;
- "[" + padr(searchstr, 6) + "]")
- ret_val := AC_ABORT // Force ACHOICE redisplay
-
- endcase
- return ret_val
-
-
- /*
- AScan2() - Case-insensitive ASCAN()
- */
- static function AScan2(array, value)
- return ascan(array, { | a | if(ISCHAR(a), upper(a) = upper(value), .F.) }, 1)
-
- //───── end of file CHP1411.PRG
-